Form Primitives
Available via @stackmates/ui-interactive/atoms
Input
Text input field with consistent styling. HeadlessUI-based with focus ring and validation states.
InputProps
| Prop | Type | Default | Description |
|---|---|---|---|
| type | 'text' | 'email' | 'password' | 'number' | 'search' | 'tel' | 'url' | 'date' | 'text' | HTML input type |
| placeholder | string | — | Placeholder text |
| disabled | boolean | false | Disable the input |
| className | string | — | Additional CSS classes |
Installation
import { Input } from '@stackmates/ui-interactive/atoms';Accessibility
- Built on HeadlessUI Input primitive with native focus management
- Supports data-invalid attribute for error state styling
- Pair with Label for accessible form fields
Checkbox
Radix checkbox with check and indeterminate indicators.
CheckboxProps
| Prop | Type | Default | Description |
|---|---|---|---|
| checked | boolean | 'indeterminate' | — | Controlled checked state |
| onCheckedChange | (checked: boolean) => void | — | Change handler |
| disabled | boolean | false | Disable the checkbox |
Installation
import { Checkbox } from '@stackmates/ui-interactive/atoms';Accessibility
- Built on Radix Checkbox with full keyboard support (Space to toggle)
- Supports indeterminate state for partial selections
- Focus ring visible on keyboard navigation
Label
Form label element with optional required indicator. Built on Radix Label primitive.
LabelProps
| Prop | Type | Default | Description |
|---|---|---|---|
| children* | ReactNode | — | Label text content |
| required | boolean | false | Show red asterisk indicator |
| htmlFor | string | — | Associated input ID |
Installation
import { Label } from '@stackmates/ui-interactive/atoms';Accessibility
- Renders as Radix Label with automatic htmlFor association
- Required asterisk is decorative — pair with aria-required on the input
- Responds to disabled state via peer/group CSS selectors
Textarea
Multi-line text input with optional resize control. HeadlessUI-based.
TextareaProps
| Prop | Type | Default | Description |
|---|---|---|---|
| placeholder | string | — | Placeholder text |
| resizable | boolean | true | Allow vertical resize |
| disabled | boolean | false | Disable the textarea |
| rows | number | — | Visible text rows |
Installation
import { Textarea } from '@stackmates/ui-interactive/atoms';Accessibility
- Built on HeadlessUI Textarea with native focus management
- Supports data-invalid for error states
- Pair with Label for accessible form fields
Switch
Toggle switch with 20+ color variants. HeadlessUI-based with smooth transitions.
SwitchProps
| Prop | Type | Default | Description |
|---|---|---|---|
| checked | boolean | — | Controlled on/off state |
| onChange | (checked: boolean) => void | — | Change handler |
| color | Color | 'dark/zinc' | Color theme when checked |
| disabled | boolean | false | Disable the switch |
Installation
import { Switch } from '@stackmates/ui-interactive/atoms';Accessibility
- Built on HeadlessUI Switch with role="switch" and aria-checked
- Keyboard accessible via Space to toggle
- Focus ring visible with outline offset
Toggle
Pressable toggle button with variant and size options. CVA-styled.
ToggleProps
| Prop | Type | Default | Description |
|---|---|---|---|
| pressed | boolean | — | Controlled pressed state |
| variant | 'default' | 'outline' | 'default' | Visual variant |
| size | 'default' | 'sm' | 'lg' | 'default' | Toggle size |
Installation
import { Toggle } from '@stackmates/ui-interactive/atoms';Accessibility
- Uses aria-pressed to communicate toggle state
- Renders as native <button> with keyboard support
- data-state attribute provides CSS hook for on/off styling
Slider
Range input with styled thumb and track. Supports controlled and uncontrolled usage with custom min/max/step.
SliderProps
| Prop | Type | Default | Description |
|---|---|---|---|
| value | number | — | Current value (controlled) |
| defaultValue | number | — | Default value for uncontrolled usage |
| min | number | 0 | Minimum value |
| max | number | 100 | Maximum value |
| step | number | 1 | Step increment between values |
| onValueChange | (value: number) => void | — | Called when value changes |
Installation
import { Slider } from '@stackmates/ui-interactive/atoms';Usage
Controlled with display
const [value, setValue] = useState(50);
<Slider value={value} onValueChange={setValue} />Custom range
<Slider min={0} max={10} step={0.5} defaultValue={5} />Accessibility
- Renders as native <input type="range"> for full browser accessibility
- Focus-visible ring with offset for keyboard navigation
- Disabled state uses cursor-not-allowed and reduced opacity
- Pair with Label for accessible form fields
CheckboxTW
HeadlessUI checkbox with 20+ color variants, indeterminate support, and CheckboxGroup/CheckboxField layout helpers.
CheckboxTWProps
| Prop | Type | Default | Description |
|---|---|---|---|
| color | Color | 'dark/zinc' | Color theme when checked (20+ color options including dark/zinc, blue, green, red, etc.) |
| checked | boolean | — | Controlled checked state |
| onChange | (checked: boolean) => void | — | Change handler |
| disabled | boolean | false | Disable the checkbox |
| className | string | — | Additional CSS classes |
Installation
import { CheckboxTW, CheckboxField, CheckboxGroup } from '@stackmates/ui-interactive/atoms';Usage
With field layout
<CheckboxGroup>
<CheckboxField>
<CheckboxTW checked={checked} onChange={setChecked} color="blue" />
<Label>Accept terms</Label>
</CheckboxField>
</CheckboxGroup>Color variants
<CheckboxTW color="green" checked onChange={handleChange} />
<CheckboxTW color="red" checked onChange={handleChange} />Accessibility
- Built on HeadlessUI Checkbox with full keyboard support (Space to toggle)
- CheckboxField provides grid layout linking label to control via data-slot attributes
- Focus ring uses outline-offset-2 with blue-500 for clear keyboard navigation visibility
- Supports forced-colors mode for Windows high contrast
SwitchRx
Radix-based toggle switch with async action prop for optimistic server mutations.
SwitchRxProps
| Prop | Type | Default | Description |
|---|---|---|---|
| checked | boolean | — | Controlled checked state |
| onCheckedChange | (checked: boolean) => void | — | Change handler (Radix convention) |
| action | (checked: boolean) => void | Promise<void> | — | Async action prop — uses useOptimistic for instant flip, auto-reverts on failure |
| disabled | boolean | false | Disable the switch |
| className | string | — | Additional CSS classes |
Installation
import { Switch } from '@stackmates/ui-interactive/atoms';
// Note: Exported as "Switch" from the SwitchRx moduleUsage
Controlled
const [enabled, setEnabled] = useState(false);
<Switch checked={enabled} onCheckedChange={setEnabled} />With async action (optimistic)
<Switch
checked={feature.enabled}
action={async (checked) => {
await toggleFeatureAction(feature.id, checked);
}}
/>Accessibility
- Built on Radix Switch with role="switch" and aria-checked state
- Keyboard accessible via Space to toggle checked state
- Focus ring uses 3px ring with ring-ring/50 for clear visibility
- data-pending attribute set during async transitions for CSS styling hooks
TextareaRx
Minimal textarea with field-sizing-content for auto-grow, aria-invalid styling, and dark mode support.
TextareaRxProps
| Prop | Type | Default | Description |
|---|---|---|---|
| placeholder | string | — | Placeholder text |
| disabled | boolean | false | Disable the textarea |
| rows | number | — | Visible text rows |
| className | string | — | Additional CSS classes |
| aria-invalid | boolean | — | Marks the textarea as invalid with destructive ring styling |
Installation
import { Textarea } from '@stackmates/ui-interactive/atoms';
// Note: Exported as "Textarea" from the TextareaRx moduleUsage
Basic
<Textarea placeholder="Enter description..." />With validation error
<Textarea
placeholder="Required field"
aria-invalid={!!errors.description}
/>
<ErrorMessage message={errors.description} />Accessibility
- Uses field-sizing-content CSS property for content-driven auto-grow without JavaScript
- aria-invalid triggers destructive ring styling for clear error indication
- Focus ring uses 3px ring with border-ring transition for smooth keyboard navigation