Input
Text-entry control with validation, icons, read-only states, and character limits
The Input component is a text-entry control for forms, search fields, settings, and other places where a user enters or reviews a single-line value. It wraps a native <input> while adding a consistent label, description, validation message, icon slots, loading and disabled states, clear actions, visual variants, and character-limit feedback.
The component preserves native input behavior and forwards native input attributes, so browser features such as type, name, autoComplete, placeholder, required, readOnly, maxLength, and form participation work as expected.
Installation
Import Input from the UI package. Use icons from @mosmox-ui/icons for consistent framework visuals.
import { MagnifyingGlass as Search } from '@mosmox-ui/icons';
import { Input } from '@mosmox/ui';Basic usage
<Input label="Project name" placeholder="Enter a project name" />Use required when the field must contain a value. The component adds an asterisk to the label and forwards the native required attribute to the input.
<Input label="Email address" type="email" required placeholder="[email protected]" />Content and value management
The component supports both uncontrolled and controlled input patterns.
Use defaultValue when the component should manage its own value:
<Input label="Workspace" defaultValue="Design system" />Use value and onChange when the parent owns the value:
const [query, setQuery] = useState('');
<Input
label="Search"
value={query}
onChange={(event) => setQuery(event.target.value)}
placeholder="Search projects"
/>onChange receives the native React change event. Native attributes such as id, name, type, autoComplete, inputMode, pattern, form, and tabIndex are forwarded to the underlying input.
Labels and field messaging
label renders an associated <label> and is connected to the input through its generated or supplied id. description adds supporting text below the label. error renders an error message and changes the field border and focus colors to the danger token.
<Input
label="Username"
description="Use 3–24 characters."
error="This username is already in use."
value="maria"
onChange={() => {}}
/>The component combines the description and error element IDs in aria-describedby, so assistive technology can read the available field guidance.
Variants
The variant property controls the field surface treatment.
<Input label="Outline" variant="outline" placeholder="Outline field" />
<Input label="Filled" variant="filled" placeholder="Filled field" />outlineis the default and displays a bordered surface.filleduses the control-filled background token and removes the visible border.
Sizes
The size property controls minimum height, padding, and input typography.
<Input label="Default" size="default" placeholder="Default size" />
<Input label="Small" size="sm" placeholder="Small size" />
<Input label="Extra small" size="xs" placeholder="Extra-small size" />default is the standard 40px control. sm and xs are intended for compact forms, filters, toolbars, and dense layouts.
Icons and text adornments
Use leadingIcon for an icon before the value and trailingIcon for an icon after it. Use prefix and suffix for text or other non-icon content, such as a currency symbol, unit, or URL fragment. The component reserves consistent dimensions and spacing for all adornments.
import { Calendar, MagnifyingGlass as Search } from '@mosmox-ui/icons';
<Input label="Search" leadingIcon={<Search size={16} />} placeholder="Search" />
<Input label="Start date" trailingIcon={<Calendar size={16} />} placeholder="Select a date" />
<Input label="Price" prefix="$" suffix="USD" placeholder="0.00" />Icons are visual decorations by default. If an icon conveys information that is not also present in the label or text, provide an accessible explanation through the surrounding field content.
prefix and suffix are visual adornments and are marked as decorative. Use the label or description to communicate their meaning to assistive technology.
Clear action
Set clearable to show a clear button when the field contains a value. onClear runs when the user activates that button.
const [search, setSearch] = useState('Roadmap');
<Input
label="Search"
value={search}
onChange={(event) => setSearch(event.target.value)}
clearable
onClear={() => setSearch('')}
/>The clear action is hidden when the value is empty, while the input is disabled or loading, or when the input is read-only. While the clear action is visible, it takes precedence over trailingIcon.
For a controlled input, the parent must update value in onClear:
<Input
label="Search"
value={query}
onChange={(event) => setQuery(event.target.value)}
clearable
onClear={() => setQuery('')}
/>Read-only values
Use the native readOnly attribute when a value should be displayed but not edited. The component shows a lock icon at the trailing edge to make the non-editable state clear.
<Input label="Account ID" value="acct_2048" readOnly />Read-only fields remain focusable and can be selected or copied. They are different from disabled fields, which are unavailable for interaction and are excluded from normal form submission.
Character limits
Pass maxLength to limit the number of characters accepted by the native input. When maxLength is present, the component automatically renders a counter below the field on the right in the form current / maximum.
<Input
label="Short description"
placeholder="Describe the project"
maxLength={120}
/>The browser prevents additional input after the limit is reached. The counter updates as the value changes and works with both controlled and uncontrolled inputs.
Loading and disabled states
Use loading while the value or surrounding operation is being resolved. Loading prevents editing and shows a loader. Use disabled when the field is unavailable.
<Input label="Loading value" value="Loading…" loading readOnly />
<Input label="Unavailable" value="Unavailable value" disabled readOnly />loading and disabled are forwarded to the native input as non-editable states. The visual treatment uses the component's disabled opacity and cursor styles.
Full width
Set fullWidth when the field should fill its parent container.
<Input fullWidth label="Full-width field" placeholder="Uses the available width" />The field has a minimum width of 100px so it remains usable in compact layouts. Use fullWidth when the input should fit the available width of a narrow parent, such as a compact dialog or grid column.
Validation states
Pass an error string when validation fails. The presence of a non-empty error activates the error border and error focus treatment.
<Input
label="Password"
type="password"
error="Password must contain at least 12 characters."
/>For custom validation logic, keep the validation state in the parent and pass the current message to error.
Accessibility
The component keeps native input semantics and connects the field content for assistive technology:
labelis associated with the input throughhtmlForandid;descriptionanderrorare referenced througharia-describedby;errorsetsaria-invalidunless an explicitaria-invalidvalue is provided;requiredis forwarded to the native input;readOnlyuses the native read-only behavior and adds a visual lock cue;- the character counter uses a polite live region so updates can be announced without interrupting the user;
- loading and disabled fields cannot be edited;
- native keyboard, focus, selection, form, and browser validation behavior is preserved.
Do not rely on placeholder text as the only field label. Use label for the field name and description for supporting instructions.
Styling model
Input styling is split between shared theme tokens and component behavior. Shared values such as colors, typography, radius, spacing, icon size, and control gaps come from the theme token layer. Input-specific layout and state rules remain in Input.css.
Global theme values can be customized with ConfigProvider:
import { ConfigProvider, Input } from '@mosmox/ui';
<ConfigProvider
theme={{
colors: {
controlBorder: '#C7D2FE',
controlFilled: '#F8FAFC',
controlIcon: '#667085',
dangerText: '#B42318',
placeholder: '#98A2B3',
},
radius: '6px',
typography: { fontWeightMedium: 500 },
}}
>
<Input label="Themed input" placeholder="Uses shared tokens" />
</ConfigProvider>API Reference
Input-specific properties
| Property | Type | Default | Description |
|---|---|---|---|
label | string | — | Associated field label. |
description | string | — | Supporting text displayed below the label. |
error | string | — | Validation message; also activates the invalid visual state. |
variant | InputVariant | outline | outline or filled. |
size | InputSize | default | default, sm, or xs. |
leadingIcon | ReactNode | — | Content rendered before the input value. |
trailingIcon | ReactNode | — | Content rendered after the input value. Hidden while the clear action is visible. |
prefix | ReactNode | — | Decorative text or content before the input value, such as $ or https://. |
suffix | ReactNode | — | Decorative text or content after the input value, such as kg or USD. |
clearable | boolean | false | Shows a clear action when a non-empty value can be edited. |
onClear | () => void | — | Called when the clear action is activated. |
loading | boolean | false | Prevents editing and shows a loading indicator. |
fullWidth | boolean | false | Expands the field to the available container width. |
inputClassName | string | — | Additional class name applied to the native input. |
className | string | — | Additional class name applied to the field wrapper. |
Native input properties
Input accepts the native InputHTMLAttributes<HTMLInputElement> properties except for the native size attribute, which is replaced by the component's visual size property.
| Property | Type | Default | Description |
|---|---|---|---|
value | `string | number | readonly string[]` |
defaultValue | `string | number | readonly string[]` |
onChange | ChangeEventHandler<HTMLInputElement> | — | Called when the value changes. |
maxLength | number | — | Maximum number of characters. Enables the current / maximum counter. |
readOnly | boolean | false | Prevents editing while keeping the field focusable and selectable. |
disabled | boolean | false | Disables interaction with the native input. |
required | boolean | false | Marks the field as required for native form validation. |
type | string | text | Native input type such as text, email, password, or search. |
placeholder | string | — | Placeholder shown when the value is empty. |
name | string | — | Form submission name. |
id | string | generated | Input ID used to associate the label and messages. |
autoComplete | string | — | Browser autocomplete hint. |
aria-label | string | — | Accessible name when a visible label is not used. |
aria-describedby | string | generated | Additional description IDs; component message IDs are appended. |
aria-invalid | `boolean | 'true' | 'false'` |
All other supported native input properties and event handlers are forwarded to the underlying <input> element.