Diamond Diamond

ui · 6 variants · 1 categories

Calendar

Date display — month grid, agenda, year heatmap, range selection.

npx "@rueda.dev/gems-diamond" add calendar
§01

Display

6 variants
April 2026
S
M
T
W
T
F
S
month
April 2026
M
T
W
T
F
S
S
minimal
April 2026
S
M
T
W
T
F
S
week
agenda
year
April 2026
S
M
T
W
T
F
S
range

Usage Guide

How to wire up this component in your app — props, callbacks, customization, and the conventions Diamond shares across the library.

Click handlers

By default, every cell is rendered as a real <button> but nothing happens on click. Pass any of these to react:

PropTypeDescription
onDayClick(date, event) => voidFires on every day cell click. Receives the JS Date and the React mouse event.
onSelect(date) => voidConvenience alias that also fires on day click. Use whichever reads better in your code. Both fire together if both are provided.
onMonthClick(monthIndex, event) => voidFires when a month tile is clicked in the year variant.
onAgendaItemClick(item, index, event) => voidFires when an agenda row is clicked in the agenda variant.
onPrevMonth / onNextMonth() => voidHeader chevrons only render when these are provided. The component never mutates `month` on its own.

Open a modal on day click

<Calendar
  variant="month"
  events={events}
  onDayClick={(date) => {
    setModalDate(date);
    setModalOpen(true);
  }}
/>

Custom rendering

For total control of what each cell looks like, pass a render override. You still get the default classes and click handler — combine them with whatever extra UI you want.

PropTypeDescription
renderDay(info) => ReactNodeinfo has date, muted, isToday, isSelected, inRange, event, defaultClassName, and handleClick.
renderMonth(info) => ReactNodeFor the year grid. Receives index, name, isCurrent, isHighlighted, defaultClassName.
renderAgendaItem(info) => ReactNodeFor agenda rows. Receives item, index, defaultClassName.
<Calendar
  variant="month"
  renderDay={({ date, defaultClassName, event }) => (
    <button
      type="button"
      className={defaultClassName + " relative"}
      onClick={() => openDetails(date)}
    >
      {date.getDate()}
      {event && (
        <span className="absolute bottom-1 size-1 rounded-full bg-rose-500" />
      )}
    </button>
  )}
/>

Events and ranges

  • events accepts an array of { date, label?, color?, meta? }. Days with an event get a tinted background; color overrides the accent for that day.
  • range is purely visual highlight: { start, end }. You manage range selection in your own state.
  • selected highlights one cell. The component never sets state itself — keep your ownuseState and update it from onDayClick.
  • weekStartsOn (0=Sun, 1=Mon) and weekdays (custom 7-string array) control the header row.

Universal patterns

Every Diamond component shares the same prop conventions, so once you learn one you can predict the others.

  • variant — discriminated union of every visual option. Categories shown above are docs-only metadata; the prop is a flat string union.
  • accent — any CSS color string. Overrides --diamond-accent just for that instance via inline style. Cascades into hover, ring, and selection states.
  • asChild (when present) — renders the underlying primitive via @radix-ui/react-slot, letting you compose with <Link>, motion.button, etc.
  • className — merged with internal Tailwind classes via cn(). Use it to override layout, spacing, or colors.
  • Native HTML attributes (onClick, aria-*, data-*, ref, etc.) flow through to the root element without any whitelist.
  • Diamond is the skin: zero domain state, zero fetch, zero providers. You wire data and reactions in your app code; the components just render and emit events.