# Age Gate Date Field

> A date of birth that decides whether someone is old enough, with the exact date they become eligible, without ever blocking typing. Use this when a product or purchase has a minimum age and the person should learn when they will qualify.

A shadcn/ui block from the [@tealmac](https://ui.tealmac.com/?utm_source=shadcn.exchange) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/tealmac/age-gate-date-field).

- Page, with a live preview: https://shadcn.exchange/r/tealmac/age-gate-date-field
- Screenshot: https://shadcn.exchange/shot/tealmac/age-gate-date-field/light.png
- Registry item: https://ui.tealmac.com/r/age-gate-date-field.json
- Listed: 2026-11-01, source last changed 2026-11-01

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/tealmac/age-gate-date-field.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `@tealmac/date-field`, `@tealmac/date-time-core`

## Files

### `registry/patterns/age-gate-date-field/age-gate-date-field.tsx`

```tsx
"use client"

import * as React from "react"

import { DateField } from "@/components/ui/date-field"
import {
  addYears,
  formatDate,
  resolveLocale,
  today as todayISO,
} from "@/components/ui/date-time-core"

export interface AgeGateDateFieldProps {
  minAge?: number
  onValueChange?: (date: string | null, eligible: boolean) => void
  today?: string
  locale?: string
}

/** The day a person born on `birth` turns `minAge` (29 February becomes 1 March in other years). */
export function eligibleOn(birth: string, minAge: number) {
  const d = addYears(birth, minAge)
  return birth.slice(5) === "02-29" && d.slice(5) === "02-28"
    ? `${d.slice(0, 4)}-03-01`
    : d
}

export function AgeGateDateField({
  minAge = 18,
  onValueChange,
  today,
  locale,
}: AgeGateDateFieldProps) {
  const loc = resolveLocale(locale)
  const now = today ?? todayISO()
  const [date, setDate] = React.useState<string | null>(null)
  const from = date ? eligibleOn(date, minAge) : null
  const eligible = !!from && from <= now

  return (
    <div className="flex flex-col gap-1.5">
      <DateField
        label="Date of birth"
        locale={loc}
        value={date}
        invalid={!!date && !eligible}
        onValueChange={(next) => {
          setDate(next)
          onValueChange?.(next, !!next && eligibleOn(next, minAge) <= now)
        }}
      />
      <p
        role="status"
        className={
          date && !eligible
            ? "text-destructive text-sm"
            : "text-muted-foreground text-sm"
        }
      >
        {!from
          ? `You must be ${minAge} or older.`
          : eligible
            ? "Thanks, you can continue."
            : `You can sign up from ${formatDate(from, loc, { dateStyle: "medium" })}.`}
      </p>
    </div>
  )
}
```
