Input
A single-line native text input in a bordered box, with optional icons and text affixes. Inside a Field it is labelled, described and validated by the Field.
Import
import { Input } from '@nizivo/react/input';
// Once per app (Getting started), after
// @nizivo/tokens/tokens.css and @nizivo/react/css/base.css
import '@nizivo/react/css/input.css';Static or interactive
Client. It always ships its client leaf, which reads its Field through FieldScope, so a page
with an Input also loads FieldScope. The server HTML is a native <input> that works before
hydration. How to choose.
Text size on touch screens
Under a coarse pointer (a phone or a tablet), the text, the placeholder and the affixes are 16 px
(Body/L) instead of 14 px (Body/M) at every size, because iOS Safari zooms the page into a focused
field whose text is smaller than 16 px. The box keeps its 32, 40 or 48 px height. --nz-input-font
replaces the font on every pointer, so a page that sets it also decides whether iOS zooms.
Examples
Basic
Inside a Field: the label, help text and native validation messages are wired for you.
import type { JSX } from 'react';
import { Field } from '@nizivo/react/field';
import { Input } from '@nizivo/react/input';
export function InputExample(): JSX.Element {
return (
<Field
label="Product title"
description="Shown on product pages and checkout."
required
messages={{ valueMissing: 'Enter a product title.' }}
>
<Input name="title" placeholder="e.g. Stoneware mug" />
</Field>
);
}
Sizes
32, 40 and 48 px, the heights of Button and Select.
import type { JSX } from 'react';
import { Input } from '@nizivo/react/input';
export function InputSizesExample(): JSX.Element {
return (
<div style={{ display: 'grid', gap: 12, maxInlineSize: 320 }}>
<Input size="sm" aria-label="Small" placeholder="Small" />
<Input aria-label="Medium" placeholder="Medium" />
<Input size="lg" aria-label="Large" placeholder="Large" />
</div>
);
}
Slots
Decorative icons, and text affixes that join the input's description. A press anywhere in the box focuses the input.
import type { JSX } from 'react';
import { Field } from '@nizivo/react/field';
import { Input } from '@nizivo/react/input';
/** Stands in for an `@nizivo/icons` glyph (a magnifier). */
function SearchMark(): JSX.Element {
return (
<svg
viewBox="0 0 24 24"
width="1em"
height="1em"
fill="none"
stroke="currentColor"
strokeWidth={1.92}
strokeLinecap="round"
>
<circle cx="11" cy="11" r="7" />
<path d="m20 20-4-4" />
</svg>
);
}
export function InputSlotsExample(): JSX.Element {
return (
<div style={{ display: 'grid', gap: 12, maxInlineSize: 320 }}>
<Input type="search" aria-label="Search products" leadingIcon={<SearchMark />} />
<Field label="Price">
<Input type="number" inputMode="decimal" prefix="₹" suffix="per kg" defaultValue="240" />
</Field>
</div>
);
}
States
An error from the server, read-only and disabled.
import type { JSX } from 'react';
import { Field } from '@nizivo/react/field';
import { Input } from '@nizivo/react/input';
export function InputStatesExample(): JSX.Element {
return (
<div style={{ display: 'grid', gap: 16, maxInlineSize: 320 }}>
<Field label="Email" error="Enter an email address like name@example.com.">
<Input type="email" defaultValue="anna@" />
</Field>
<Field label="SKU" readOnly>
<Input defaultValue="MUG-0042" />
</Field>
<Field label="Barcode" disabled>
<Input defaultValue="8901234567890" />
</Field>
</div>
);
}
Props
Client component Renders data-slot="input" with the class nz-input. Props: InputProps. Source: src/input/input.client.tsx.
| Name | Type | Default | Description |
|---|---|---|---|
invalid | boolean | – | An error message is presented for this input (§8.3). Inside a Field, the Field sets it; an explicit value here wins. |
leadingIcon | ReactNode | – | Decorative icon before the value ( |
prefix | ReactNode | – | Text before the value, such as a currency sign; joined to the input's |
render | RenderProp<InputState> | – | Composition of the root, the bordered box around the native |
size | ControlSize"sm""md""lg" | 'md' | 32 / 40 / 48 px, as Button and Select. |
suffix | ReactNode | – | Text after the value, such as a unit; joined to the input's |
trailingIcon | ReactNode | – | Decorative icon after the value ( |
type | InputType"text""email""search""password""number""tel""url" | 'text' |
- Also takes every attribute of
<input>exceptchildren,prefix,size,type. (Omit<ComponentPropsWithRef<"input">, "type" | "size" | "prefix" | "children">)
render takes an element, or, in client code, a function of the props and this state (InputState):
| Name | Type | Default | Description |
|---|---|---|---|
disabledrequired | boolean | – | |
invalidrequired | boolean | – | An error message is presented (the Field's, or the |
readOnlyrequired | boolean | – | |
sizerequired | ControlSize"sm""md""lg" | – |
Other exports
InputPropstypeimport type { InputProps } from '@nizivo/react/input'The props of
Input, listed above.InputStatetypeimport type { InputState } from '@nizivo/react/input'The render state of
Input, listed above.InputTypetypeimport type { InputType } from '@nizivo/react/input'Text-like input types; the others (checkbox, file, date, …) are other components.
type InputType = "text" | "email" | "search" | "password" | "number" | "tel" | "url"
Data attributes and slots
Style parts by class (.nz-<slot>) and state by data attribute. Attribute meanings come from contracts/vocabulary.json.
| Slot | Rendered by | Data attributes |
|---|---|---|
input.nz-input | Inputroot (takes render); interactive, focus: within |
|
input-control.nz-input-control | Inputinner element (CSS only) | none |
input-icon.nz-input-icon | Inputinner element (CSS only) | none |
input-prefix.nz-input-prefix | Inputinner element (CSS only) | none |
input-suffix.nz-input-suffix | Inputinner element (CSS only) | none |
CSS hooks
Set a hook on the component's class or any ancestor to restyle it without specificity games; leave it unset for the default shown.
| Hook | Default | Read as |
|---|---|---|
--nz-input-affix-fg | --nz-text-secondary |
|
--nz-input-bg |
|
|
--nz-input-bg-disabled | --nz-bg-disabled |
|
--nz-input-border |
|
|
--nz-input-border-hover |
|
|
--nz-input-fg | --nz-text-primary |
|
--nz-input-fg-disabled | --nz-text-disabled |
|
--nz-input-font |
|
|
--nz-input-gap |
|
|
--nz-input-height |
|
|
--nz-input-icon-fg | --nz-icon-secondary |
|
--nz-input-padding-inline | --nz-space-3 |
|
--nz-input-placeholder-fg | --nz-text-tertiary |
|
--nz-input-radius |
|
|
Layers: nz.components. Classes: .nz-input, .nz-input-control, .nz-input-icon, .nz-input-prefix, .nz-input-suffix.
Tokens this stylesheet reads (29)
--nz-bg-disabled, --nz-bg-subtle, --nz-bg-surface, --nz-border-control, --nz-border-control-hover, --nz-border-critical, --nz-border-subtle, --nz-border-width-default, --nz-border-width-focus, --nz-duration-fast, --nz-easing-standard, --nz-focus-halo, --nz-focus-halo-critical, --nz-font-body-l, --nz-font-body-m, --nz-icon-secondary, --nz-radius-md, --nz-radius-sm, --nz-size-control-lg, --nz-size-control-md, --nz-size-control-sm, --nz-size-icon-sm, --nz-space-1-5, --nz-space-2, --nz-space-3, --nz-text-disabled, --nz-text-primary, --nz-text-secondary, --nz-text-tertiary
Accessibility
These parts are interactive. Each gets the focus outline and touch-action rule from @nizivo/react/css/base.css (the nz.base layer), so the floor survives a restyle:
input: draws the outline when the field inside it has focus.
Keyboard
| Keys | Action |
|---|---|
| Tab | Moves focus to the input. The whole box draws the focus outline; a press anywhere on the box, its icons or its affixes, focuses the input. |
| Enter | Submits the form the input belongs to (the browser's implicit submission). Inside a Field, a failed constraint shows its message under the input and focuses the first invalid control. |
Source: a native <input> (input.client.tsx); the box's mousedown handler forwards focus to it. The browser lane (test/browser/text-controls.spec.tsx) checks the focus outline, the hit area and inline validation on submit.
Figma
Node ids from design/component-map.json, which nz gen writes from component.json. The links open the Nizivo Figma library, which may ask you to sign in.
- Canonical: Figma node
7275:11397 - Ghost masters: Figma node
745:187