# Persian Calendar Picker

> A right-to-left Persian (Solar Hijri) date picker with Persian month names and digits, a Saturday week start, Nowruz marked and an ISO value. Use this when your app serves Persian-speaking users who expect their own calendar, direction and week.

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/persian-calendar-picker).

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

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/tealmac/persian-calendar-picker.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/calendar-grid`, `@tealmac/date-time-core`

## Files

### `registry/patterns/persian-calendar-picker/persian-calendar-picker.tsx`

```tsx
"use client"

import * as React from "react"

import { CalendarGrid } from "@/components/ui/calendar-grid"
import {
  addDays,
  calendarFullLabel,
  calendarParts,
  eachDay,
  endOfMonth,
  startOfMonth,
  today as todayISO,
} from "@/components/ui/date-time-core"

export interface PersianCalendarPickerProps {
  value?: string | null
  defaultValue?: string | null
  onValueChange?: (value: string | null) => void
  locale?: string
  today?: string
}

/** The first day of the Persian year. */
export function isNowruz(iso: string) {
  const p = calendarParts(iso, "persian", "en")
  return p.month === 1 && p.day === 1
}

export function PersianCalendarPicker({
  value,
  defaultValue = null,
  onValueChange,
  locale = "fa-IR",
  today,
}: PersianCalendarPickerProps) {
  const now = today ?? todayISO()
  const [inner, setInner] = React.useState<string | null>(defaultValue)
  const [month, setMonth] = React.useState(defaultValue ?? now)
  const date = value === undefined ? inner : value
  // Nowruz can sit in the neighbouring Gregorian month's grid, so look a week either side.
  const visible = eachDay(
    addDays(startOfMonth(month), -7),
    addDays(endOfMonth(month), 7)
  )
  const markers = Object.fromEntries(
    visible.filter(isNowruz).map((d) => [d, "Nowruz"])
  )

  return (
    <div dir="rtl" lang={locale} className="flex w-fit flex-col gap-2">
      <CalendarGrid
        label="تقویم"
        calendar="persian"
        locale={locale}
        today={now}
        firstDay={6}
        month={month}
        onMonthChange={setMonth}
        markers={markers}
        value={date}
        onValueChange={(d) => {
          if (value === undefined) setInner(d as string | null)
          onValueChange?.(d as string | null)
        }}
        className="border"
      />
      <p role="status" className="text-sm">
        {date
          ? calendarFullLabel(date, "persian", locale)
          : "یک روز را انتخاب کنید"}
      </p>
    </div>
  )
}
```
