Component architecture
The Klayd React package
One local implementation for reusable components and their Visual Review examples.
@klayd/react currently lives in packages/react. Its name is provisional, npm ownership has not been verified, and nothing has been published. Do not install this name from the public registry expecting this implementation.
Local setup
Run npm install from the Klayd repository root. npm links the workspace automatically. The app can then import Accordion directly from the package:
import { Accordion } from '@klayd/react';
export function DesignDetails() {
return (
<Accordion variant="surface" defaultExpandedKeys={["design"]}>
<Accordion.Item value="design">
<Accordion.Heading level={3}>
<Accordion.Trigger>
Design settings
<Accordion.Indicator />
</Accordion.Trigger>
</Accordion.Heading>
<Accordion.Panel>Use shared theme tokens for a consistent kit.</Accordion.Panel>
</Accordion.Item>
</Accordion>
);
}This is a source-first package: its consumer must process TypeScript, JSX, CSS, and CSS Modules. React 19 is required. It does not yet ship compiled JavaScript or declaration files.
Composition and state
Use Item, Heading, Trigger, Indicator, and Panel when content needs custom layout. Give each item a unique value. Keep action buttons outside the trigger and use a heading level appropriate to the page.
Use defaultExpandedKeys for uncontrolled state, or supply both expandedKeys and onExpandedChange for application-controlled state. The items convenience API uses these same compound parts; choose either items or children, not both.
import { useState } from 'react';
import { Accordion } from '@klayd/react';
// Inside your component:
const [expandedKeys, setExpandedKeys] = useState<string[]>([]);
<Accordion expandedKeys={expandedKeys} onExpandedChange={setExpandedKeys}>
{/* Compose Accordion.Item children here. */}
</Accordion>Theme and accessibility
The editor supplies theme variables for text, muted text, surfaces, borders, accent color, spacing, radii, and motion. Accordion inherits those settings and respects reduced motion. Native buttons provide Enter and Space activation; triggers and panels share accessible IDs. Collapsed panels are hidden from assistive technology and their content is inert.
For standalone use, provide --text, --muted, --border, --accent, --review-surface-muted, --review-space, and --review-radius at a theme boundary. Motion uses --motion-standard and --motion-ease. These token names are provisional; system-color and spacing fallbacks are provided.
What has migrated?
The target is the entire component catalog. Package migration is not complete, and changing an import alone does not make an editor renderer a reusable component.
- Accordion, Alert, Avatar, Badge, Breadcrumbs, Button, ButtonGroup, Card, Chip, Checkbox, Radio, Select, TextArea, Switch, Input, TextField, Autocomplete, Modal, AlertDialog, Popover, Tooltip, Calendar, RangeCalendar, DatePicker, DateRangePicker, Tabs, Menu, Pagination, DateField, NumberField, InputOTP, Slider, Spinner, Progress, Meter, and ProgressCircle implementations now live in the package. Their Visual Review examples use those implementations.
- Demo data, example layouts, and editor-specific styling adapters remain in the app. Autocomplete still carries legacy selector-based styles that need further isolation.
- The remaining catalog components still need migration. Editor calendar presets, markers, time controls, and per-state styling remain editor-specific; they are not part of the new package calendar API.
- Export generators have not migrated to this package. User-exported kits remain separate artifacts with their own package names and APIs.
import { Accordion, Alert, Avatar, Badge, Breadcrumbs, Button, ButtonGroup, Card, Chip, Checkbox, Radio, Select, TextArea, Switch, Input, TextField, Autocomplete, Modal, AlertDialog, Popover, Tooltip, Calendar, RangeCalendar, DatePicker, DateRangePicker, Tabs, Menu, Pagination, DateField, NumberField, InputOTP, Slider, Spinner, Progress, Meter, ProgressCircle } from '@klayd/react';The old ./components/ReviewAccordion path remains a compatibility re-export. New code should use @klayd/react. There is no @klayd/react.module.css entry: component CSS is imported internally.
Overlay composition
Modal, AlertDialog, and Popover expose Trigger, Content, Title, and Close. Tooltip exposes Trigger and Content; keep its content non-interactive. Use isOpen and onOpenChange for controlled state, or defaultOpen for uncontrolled state. Always give dialogs a Title or an accessible label.
import { Modal } from '@klayd/react';
export function ReviewDetails() {
return (
<Modal>
<Modal.Trigger>Review details</Modal.Trigger>
<Modal.Content>
<Modal.Title>Review details</Modal.Title>
<p>Check the latest updates with your team.</p>
<Modal.Close>Return to workspace</Modal.Close>
</Modal.Content>
</Modal>
);
}Escape dismisses overlays and restores trigger focus. Modal allows outside dismissal by default; AlertDialog does not. Popover and Tooltip accept placement on Content. Portals inherit the surrounding theme; avoid roots inside clipping or transformed ancestors. System reduced-motion preferences disable entry animation.
Calendar and date selection
Calendar and RangeCalendar provide a navigable month. DatePicker and DateRangePicker combine those calendars with editable date segments. Pass a label to pickers, and use date values from @internationalized/date. Use value and onChange for controlled state, or defaultValue for uncontrolled state.
import { useState } from 'react';
import { DatePicker } from '@klayd/react';
import { parseDate, type DateValue } from '@internationalized/date';
export function ReviewDate() {
const [value, setValue] = useState<DateValue | null>(parseDate('2026-09-07'));
return <DatePicker label="Review date" value={value} onChange={setValue} />;
}Use isDisabled, isReadOnly, minValue, maxValue, and isDateUnavailable to constrain selection. Range values contain start and end dates. React Aria handles localized segments, keyboard navigation, and validation. Editor-only presets, markers, time controls, and canvas overrides remain separate.
Navigation controls
Tabs exposes List, Item, and Panel. Match item and panel IDs and label the List. Use selectedKey and onSelectionChange for controlled selection. Disabled items are skipped by keyboard navigation.
The editor’s Dropdown examples use Menu, with Trigger, Content, and Item. Handle onAction on Content or an item; rich items need textValue. Escape closes the menu and restores trigger focus.
Pagination uses total as a page count, page and onPageChange for controlled state, or defaultPage otherwise. It renders bounded page buttons with ellipses and labels the current page for assistive technology. The consumer handles data loading or URL navigation.
import { useState } from 'react';
import { Pagination } from '@klayd/react';
export function ResultsPages() {
const [page, setPage] = useState(1);
return <Pagination total={12} page={page} onPageChange={setPage} />;
}Additional fields
DateField provides date segments without a popup. NumberField provides numeric entry and steppers, with minValue, maxValue, step, and locale-aware formatting. Both support value/onChange and isDisabled/isReadOnly; an empty NumberField may return NaN.
Slider provides a single numeric thumb with keyboard controls, value/onChange, minValue, maxValue, step, and isDisabled. InputOTP uses one native input for paste and autofill, with value/onValueChange, native disabled/readOnly props, and a length of 1–12 digits (six by default). It normalizes ASCII digits but never verifies or submits a code automatically.
Status indicators
Progress and ProgressCircle accept label, value, minValue, maxValue, and isIndeterminate. Meter represents a measurement within a known range, not loading. Spinner exposes a visible status label; remove it when work completes. These components do not start or track background tasks automatically.
Loading animation uses the motion-loading token and stops under system reduced-motion preferences. Indeterminate progress does not announce a misleading numeric value.
Before publishing
Stabilize the theme and component APIs, migrate and test exports, produce compiled artifacts, test packed-package consumers, verify scope ownership, choose a license, and define versioned releases. Publishing requires a separate explicit approval.