Skip to main content
Components

React Form Components

15+ accessible form components: inputs, selects, checkboxes, radio groups, sliders, textareas, file uploads. All typed, all Tailwind v4 styled.

import { Input, Select, Checkbox, Switch } from "@ninna-ui/forms";
import { Field } from "@ninna-ui/forms";

<Field label="Email" htmlFor="email">
  <Input id="email" type="email" placeholder="you@example.com" />
</Field>

<Select>
  <Select.Item value="us">United States</Select.Item>
  <Select.Item value="ca">Canada</Select.Item>
</Select>

<Checkbox>Accept terms</Checkbox>
<Switch>Enable notifications</Switch>

Key features

15+ form components: Input, Select, Checkbox, Radio, Switch, Slider, Textarea, FileUpload, PinInput, NumberInput

Field wrapper with label, description, and error message

InputGroup with startElement / endElement for icons

Checkbox and Switch use onCheckedChange (not onChange)

Full ARIA compliance with Radix UI internals

FormControl for programmatic validation state

Complete form coverage

Ninna UI's @ninna-ui/forms package covers every common form control: text inputs, selects, checkboxes, radio groups, switches, sliders, textareas, file uploads, pin inputs, and number inputs. Each component is accessible, typed, and styled with Tailwind CSS v4.

Field wrapper pattern

The Field component wraps any input with a label, description, and error message — handling ARIA wiring automatically:

<Field label="Username" htmlFor="username" error="Username is taken" invalid>
  <Input id="username" placeholder="Choose a username" />
</Field>

<Field label="Bio" description="Tell us about yourself" htmlFor="bio">
  <Textarea id="bio" rows={4} />
</Field>

InputGroup for icons

Put icons inside inputs using the startElement and endElement props on InputGroup — not a leftIcon prop on Input:

import { InputGroup } from "@ninna-ui/forms";
import { Search } from "lucide-react";

<InputGroup startElement={<Search className="size-4" />}>
  <Input placeholder="Search…" />
</InputGroup>

Component Docs

FAQ