# useToday

> Today's date that rolls over at midnight and when the tab comes back, without a hydration mismatch.

Docs: https://hextaui.com/docs/use-today
Markdown: https://hextaui.com/docs/use-today.md

```tsx title="components/examples/use-today/demo.tsx"
"use client"

import { Skeleton } from "@/components/ui/skeleton"
import { useToday } from "@/hooks/use-today"

const formatter = new Intl.DateTimeFormat(undefined, { dateStyle: "full" })

function daysUntilNewYear(today: Date) {
  const next = new Date(today.getFullYear() + 1, 0, 1)
  return Math.round((next.getTime() - today.getTime()) / 86_400_000)
}

export function UseTodayDemo() {
  const today = useToday()

  return (
    <div className="flex flex-col items-center gap-1 text-center">
      {today ? (
        <>
          <p className="text-lg font-medium">{formatter.format(today)}</p>
          <p className="text-sm text-muted-foreground">
            {daysUntilNewYear(today)} days until New Year
          </p>
        </>
      ) : (
        <>
          <Skeleton className="h-6 w-56" />
          <Skeleton className="mt-1 h-4 w-36" />
        </>
      )}
    </div>
  )
}
```

## Installation

### CLI

```bash
npx shadcn@latest add https://hextaui.com/r/use-today.json
```

This adds the hook and anything it depends on.

### Manual

Copy and paste the following code into your project.

```ts title="hooks/use-today.ts"
import * as React from "react"

function toDateKey(date: Date) {
  const month = String(date.getMonth() + 1).padStart(2, "0")
  const day = String(date.getDate()).padStart(2, "0")
  return `${date.getFullYear()}-${month}-${day}`
}

function fromDateKey(key: string) {
  const [year, month, day] = key.split("-").map(Number)
  return new Date(year, month - 1, day)
}

function subscribeToday(onChange: () => void) {
  let timer: ReturnType<typeof setTimeout> | undefined

  const schedule = () => {
    const now = new Date()
    const midnight = new Date(
      now.getFullYear(),
      now.getMonth(),
      now.getDate() + 1
    )
    timer = setTimeout(
      () => {
        onChange()
        schedule()
      },
      midnight.getTime() - now.getTime() + 1000
    )
  }

  const onVisible = () => {
    if (document.visibilityState === "visible") {
      onChange()
    }
  }

  schedule()
  document.addEventListener("visibilitychange", onVisible)

  return () => {
    clearTimeout(timer)
    document.removeEventListener("visibilitychange", onVisible)
  }
}

function getTodayKey() {
  return toDateKey(new Date())
}

function getNoTodayKey() {
  return null
}

function useToday() {
  const key = React.useSyncExternalStore(
    subscribeToday,
    getTodayKey,
    getNoTodayKey
  )

  return React.useMemo(() => (key ? fromDateKey(key) : undefined), [key])
}

export { fromDateKey, getTodayKey, subscribeToday, toDateKey, useToday }
```

Update the import paths to match your project setup.

## Usage

```tsx
import { useToday } from "@/hooks/use-today"
```

```tsx
const today = useToday()

if (!today) {
  return <Skeleton className="h-5 w-40" />
}

return <p>{format(today, "PPPP")}</p>
```

Reach for it whenever a component depends on the current date, such as highlighting today, disabling past days or counting down to a deadline.

## Why not new Date()

```tsx
const today = new Date()
```

Reading the date while rendering breaks in two ways:

- **Hydration mismatches.** The server renders in its time zone, possibly hours earlier. Near midnight, server and browser disagree on the day, and React throws away the server HTML.
- **Stale dates.** A tab left open overnight keeps showing yesterday as today until something else re-renders it.

`useToday` returns `undefined` on the server and during hydration, then the local date. It also re-renders at midnight and when the tab becomes visible again, because timers in background tabs can be paused and miss midnight.

## Examples

### Date bounds

Disable past days and anything more than 30 days out. Until today is known, nothing is disabled, so the server HTML matches the first client render.

```tsx title="components/examples/use-today/bounds.tsx"
"use client"

import { addDays } from "date-fns"

import { Calendar } from "@/components/ui/calendar"
import { useToday } from "@/hooks/use-today"

export function UseTodayBounds() {
  const today = useToday()

  return (
    <Calendar
      mode="single"
      disabled={today ? [{ before: today }, { after: addDays(today, 30) }] : []}
    />
  )
}
```

### Date keys

```tsx
import {
  fromDateKey,
  getTodayKey,
  subscribeToday,
  toDateKey,
} from "@/hooks/use-today"

toDateKey(new Date(2026, 9, 5))
fromDateKey("2026-10-05")

const unsubscribe = subscribeToday(() => refreshAgenda())
```

The file also exports the pieces the hook is built from. Date keys are local `YYYY-MM-DD` strings. They compare by day, sort correctly and are safe to use as React keys or cache keys. `subscribeToday` calls you back at midnight and on tab return, outside React.

## Good to know

- The returned `Date` is midnight in local time, so comparing it with `<` or `>` compares days, not times.
- The same `Date` object comes back until the day changes, so it's safe to use in effect dependencies.
- Plan for the `undefined` render. A skeleton, or rendering without date-based limits, both work.

## API reference

### useToday()

| Returns | Description |
| --- | --- |
| `Date \| undefined` | Local midnight today. undefined on the server and while hydrating. |

### Helpers

| Export | Description |
| --- | --- |
| `toDateKey(date)` | A Date as a local YYYY-MM-DD string. |
| `fromDateKey(key)` | A YYYY-MM-DD string as a local-midnight Date. |
| `getTodayKey()` | Today's date key. |
| `subscribeToday(callback)` | Calls back at midnight and when the tab becomes visible. Returns an unsubscribe function. |

### Used by

`Calendar`, and `Date picker` through it.

## Notes for AI assistants

- Install a component with the shadcn CLI: `npx shadcn@latest add https://hextaui.com/r/<name>.json`. It adds the source, the HextaUI theme tokens and any HextaUI components it depends on. `https://hextaui.com/r/all.json` installs every component.
- The code is then owned by the project, like shadcn/ui. There is no HextaUI npm package. HextaUI is MIT licensed and free for personal and commercial use.
- Behavior and accessibility come from Base UI (`@base-ui/react`). Compose with the `render` prop, not `asChild`.
- Styling uses Tailwind CSS v4 with theme tokens. Merge classes with `cn` from the `cn` package.
- Icons come from `@tabler/icons-react`.
- Import components from `@/components/ui/<name>`, hooks from `@/hooks/<name>` and utilities from `@/lib/<name>`.

Every HextaUI doc: https://hextaui.com/llms.txt
