Skip to main content

Styling

Kalyx ships zero CSS. Every part renders semantic, unstyled HTML and exposes two styling contracts:

  1. classNames prop — a typed map of slot names → class strings, on each sub-component.
  2. data-* state attributes — emitted on interactive elements so you can style by state in CSS / Tailwind without re-rendering.

Either works alone; combine them when you want a stable class plus state-based variants.

1. The classNames prop

Every sub-component accepts a classNames object keyed by internal slot. Pass only the slots you care about.

<DatePicker.Calendar
classNames={{
grid: 'grid grid-cols-7 gap-1',
day: 'rounded p-2 hover:bg-gray-100',
daySelected: 'bg-blue-600 text-white',
dayToday: 'ring-1 ring-blue-400',
dayDisabled: 'opacity-40 cursor-not-allowed',
dayOutsideMonth: 'text-gray-300',
}}
/>

Slot keys are documented per sub-component on each component page. The state slots (daySelected, dayToday, …) are applied in addition to the base slot (day) when that state is active — so a selected day gets both day and daySelected classes.

2. data-* state attributes

For Tailwind (data-[selected]:…) or plain CSS attribute selectors, every stateful element also carries data-* attributes. They are present only when the state is active (omitted otherwise — never data-selected="false"), so [data-selected] is a reliable selector.

/* plain CSS */
.day[data-selected] { background: #2563eb; color: white; }
.day[data-today] { outline: 1px solid #60a5fa; }
.day[data-in-range] { background: #dbeafe; }
/* Tailwind v3.1+ data variants — no classNames needed */
<DatePicker.Calendar
classNames={{
day: 'rounded p-2 data-[selected]:bg-blue-600 data-[selected]:text-white data-[today]:ring-1',
}}
/>

Attribute reference

These are the attributes Kalyx emits. disabled days use the native disabled attribute and aria-disabled (not a data-* flag), so style them with :disabled or the dayDisabled slot.

Calendar day cells

AttributeEmitted byActive when
data-focusedDatePicker / RangePicker / WeekPicker / DateTimePicker .CalendarDay holds keyboard focus (roving tabindex).
data-selectedDatePicker / DateTimePicker .CalendarDay is the selected date.
data-todayall .CalendarDay is today (in displayTimezone if set).
data-outside-monthall .CalendarDay pads the 6-week view from an adjacent month.
data-range-startRangePicker / WeekPicker .CalendarDay is the range's start.
data-range-endRangePicker / WeekPicker .CalendarDay is the range's end.
data-in-rangeRangePicker / WeekPicker .CalendarDay is strictly between start and end.
data-week-numberall .Calendar (on the row <th>)Present when week numbers are shown.

Month / year cells

AttributeEmitted byActive when
data-selectedDatePicker.MonthGrid / .YearGrid, MonthPicker.Grid, YearPicker.GridCell is the selected month / year.
data-currentsame as aboveCell is the current month / year (today).
data-focusedsame as aboveCell holds keyboard focus.

Time cells

AttributeEmitted byActive when
data-selectedTimePicker.HourList / .MinuteList / .AmPmToggle (and DateTimePicker equivalents)The hour / minute / meridiem is the current value.

Presets & inputs

AttributeEmitted byActive when
data-activeDatePicker / RangePicker / DateTimePicker .PresetThe preset's resolved date matches the current value.
data-partRangePicker / WeekPicker .InputAlways — value is "start" or "end", to target each input.

Which should I use?

  • Static lookclassNames base slots (day, grid, …).
  • State variants in Tailwinddata-[selected]: / data-[today]: utilities inside a single slot class.
  • Plain CSS / design tokensdata-* attribute selectors in your stylesheet.

See the Tailwind recipe and shadcn recipe for end-to-end examples.