Forms

Inputs for accessible data entry

Text inputs with supporting labels, hints, and error text for React forms. Use them in Next.js server actions or client forms while keeping focus management predictable.

Appearance

Default, error, and success appearances

Use `appearance` for validation styling. Error sets `aria-invalid` unless you override it.

Default
Warning
Info
Error
Success

Motion presets

Optional focus and hover motion

Same preset names as the button: `lift`, `press`, `glow`, `tilt`, `bounce`, or `none`.

Lift
Press
Glow
Tilt
Bounce
None

Multiline

as="textarea"

Same CVA recipe, motion presets, and data-slot="input" as the single-line control; height uses min-height and vertical resize so longer copy stays comfortable.

File upload

as="file"

Wraps <input type="file"> with the same CVA recipe. The native file-selector button inherits the active appearance colour, and all three sizes are supported.

sm
md
lg

Checkbox

as="checkbox"

Native type="checkbox" with the same appearance tokens as text fields; size maps to control dimensions.

Appearances

Sizes

Radio

as="radio"

Native type="radio" uses the same accent mapping when checked; use a shared name for mutually exclusive options.

Appearances

Sizes

Group

Sizes

sm, md, lg

Heights align with the button scale. Pass `disabled`, `readOnly`, `autoComplete`, and any other native attribute alongside variants.

Small
Medium
Large

States

Disabled and read-only

Disabled
Read only

Controlled

Value driven by React state

Current value: (empty)

The same state is wired to the controlled example in "Input variants examples" below.

Input variants examples

Use Show output / Show code on each row to compare the live control with the JSX. Each snippet opens with a Variant line naming the axis and token.


Appearance: DEFAULT


Appearance: WARNING


Appearance: INFO


Appearance: ERROR


Appearance: SUCCESS


Appearance: VIOLET


Appearance: AMBER


Appearance: PINK


Appearance: INDIGO


Appearance: ORANGE


Animation: LIFT


Animation: PRESS


Animation: GLOW


Animation: TILT


Animation: BOUNCE


Animation: NONE


Size: SM


Size: MD


Size: LG


Pattern: TEXTAREA + GLOW


Type: PASSWORD


State: DISABLED


State: READ ONLY


Pattern: CONTROLLED


Slot: ERROR MESSAGE

This is an error message


Ring: FALSE


As: FILE


As: CHECKBOX


As: RADIO


Pattern: RADIO GROUP


Type: DATE

CSS variable overrides

Inputs CSS variables

Override these inputs variables on :root, a theme selector, or a component wrapper.

107 variables

Pattern: --zui-<component>-<slot?>-<variant?>-<property>-<state?>-dark?

:root {
  --zui-input-bg: #0000000d;
  --zui-input-fg: oklch(20.8% 0.042 265.755);
  --zui-input-shadow: 0 1px 2px rgba(15,23,42,0.08);
  --zui-input-ring-offset: oklch(98.4% 0.003 247.858);
  --zui-input-placeholder-fg: oklch(55.4% 0.046 257.417);
  --zui-input-bg-read-only: #00000008;
  --zui-input-file-border: #0000001a;
  --zui-input-file-bg: #0000001a;
  --zui-input-file-fg: oklch(37.2% 0.044 257.287);
  --zui-input-file-bg-hover: #00000026;
  --zui-input-file-fg-hover: #ffffff;
  --zui-input-checkbox-border: #0000004d;
  --zui-input-checkbox-bg: transparent;
  --zui-input-radio-border: #0000004d;
  --zui-input-radio-bg: transparent;
  --zui-input-radio-bg-read-only: transparent;
  --zui-input-radio-ring: #00000033;
  --zui-input-radio-ring-offset: oklch(98.4% 0.003 247.858);
  --zui-input-default-border: #0000001a;
  --zui-input-default-border-focus: #00000033;
  --zui-input-warning-border: oklch(79.5% 0.184 86.047 / 0.8);
  --zui-input-warning-fg: oklch(28.6% 0.066 53.813);
  --zui-input-warning-placeholder-fg: oklch(47.6% 0.114 61.907);
  --zui-input-warning-border-focus: oklch(68.1% 0.162 75.834);
  --zui-input-warning-ring-focus: oklch(85.2% 0.199 91.936 / 0.8);
  --zui-input-error-border: oklch(64.5% 0.246 16.439 / 0.8);
  --zui-input-error-fg: oklch(27.1% 0.105 12.094);
  --zui-input-error-placeholder-fg: oklch(45.5% 0.188 13.697);
  --zui-input-error-border-focus: oklch(58.6% 0.253 17.585);
  --zui-input-error-ring-focus: oklch(71.2% 0.194 13.428 / 0.8);
  --zui-input-success-border: oklch(69.6% 0.17 162.48 / 0.7);
  --zui-input-success-fg: oklch(26.2% 0.051 172.552);
  --zui-input-success-placeholder-fg: oklch(43.2% 0.095 166.913);
  --zui-input-success-border-focus: oklch(59.6% 0.145 163.225);
  --zui-input-success-ring-focus: oklch(76.5% 0.177 163.223 / 0.8);
  --zui-input-info-border: oklch(62.3% 0.214 259.815 / 0.8);
  --zui-input-info-fg: oklch(28.2% 0.091 267.935);
  --zui-input-info-placeholder-fg: oklch(42.4% 0.199 265.638);
  --zui-input-info-border-focus: oklch(54.6% 0.245 262.881);
  --zui-input-info-ring-focus: oklch(70.7% 0.165 254.624 / 0.8);
  --zui-input-violet-border: oklch(60.6% 0.25 292.717 / 0.8);
  --zui-input-violet-fg: oklch(28.3% 0.141 291.089);
  --zui-input-violet-placeholder-fg: oklch(43.2% 0.232 292.759);
  --zui-input-violet-border-focus: oklch(54.1% 0.281 293.009);
  --zui-input-violet-ring-focus: oklch(70.2% 0.183 293.541 / 0.8);
  --zui-input-amber-border: oklch(76.9% 0.188 70.08 / 0.8);
  --zui-input-amber-fg: oklch(27.9% 0.077 45.635);
  --zui-input-amber-placeholder-fg: oklch(47.3% 0.137 46.201);
  --zui-input-amber-border-focus: oklch(66.6% 0.179 58.318);
  --zui-input-amber-ring-focus: oklch(82.8% 0.189 84.429 / 0.8);
  --zui-input-pink-border: oklch(65.6% 0.241 354.308 / 0.8);
  --zui-input-pink-fg: oklch(28.4% 0.109 3.907);
  --zui-input-pink-placeholder-fg: oklch(45.9% 0.187 3.815);
  --zui-input-pink-border-focus: oklch(59.2% 0.249 0.584);
  --zui-input-pink-ring-focus: oklch(71.8% 0.202 349.761 / 0.8);
  --zui-input-indigo-border: oklch(58.5% 0.233 277.117 / 0.8);
  --zui-input-indigo-fg: oklch(25.7% 0.09 281.288);
  --zui-input-indigo-placeholder-fg: oklch(39.8% 0.195 277.366);
  --zui-input-indigo-border-focus: oklch(51.1% 0.262 276.966);
  --zui-input-indigo-ring-focus: oklch(67.3% 0.182 276.935 / 0.8);
  --zui-input-orange-border: oklch(70.5% 0.213 47.604 / 0.8);
  --zui-input-orange-fg: oklch(26.6% 0.079 36.259);
  --zui-input-orange-placeholder-fg: oklch(47% 0.157 37.304);
  --zui-input-orange-border-focus: oklch(64.6% 0.222 41.116);
  --zui-input-orange-ring-focus: oklch(75% 0.183 55.934 / 0.8);
}

/* Dark theme variables follow the same names with -dark appended. */
.dark {
  --zui-input-bg-dark: #ffffff0d;
  --zui-input-fg-dark: oklch(98.4% 0.003 247.858);
  /* ...same variables with -dark at the end */
}

What it does

Inputs expose slots for icons and affixes without breaking baseline alignment.

Wire aria-invalid when validation fails and keep error text programmatically associated.

Composition and API

Prefer compound subcomponents instead of one oversized prop bag. Export a small, documented API for your design system.

Avoid duplicating labels when placeholders are decorative only.

Common use cases

  • Collect account settings with inline validation.
  • Pair with selects and toggles for configuration wizards.
  • Capture search terms in filter drawers.
  • Power admin tables with inline editing fields.

Accessibility

Keyboard order, focus rings, and ARIA attributes should match production usage. Test with your supported browsers and assistive technologies when semantics are non-trivial.

This preview page exposes a single h1 in the hero for a clean outline.

Next.js integration notes

Colocate examples under the App Router, keep server and client boundaries explicit, and avoid pulling interactive overlays into unexpected server layouts.

Set NEXT_PUBLIC_SITE_URL so canonical and Open Graph URLs resolve on deploy.

FAQ

Does the Input component work with Next.js App Router?

Yes. Import it like any other React component; keep interactive subtrees in client components when you need hooks or browser APIs, and leave static structure in server components where possible.

Can I customize input with Tailwind CSS?

Zentauri UI exposes class-friendly variants and slots so you can extend styles with Tailwind utilities without fighting inline styles.

Is this Input implementation accessible by default?

Primitives follow sensible defaults, but accessibility depends on how you label controls, manage focus, and wire keyboard handlers in your app. Validate critical flows with keyboard-only use and screen readers.