Skip to main content

Input

A fully accessible text input component with built-in label, helper text, error handling, size variants, and WCAG-compliant focus behavior.


Usage

Basic usage

import { Input } from '@nofinite/nui';

<Input label="Email" placeholder="email@example.com" />;

With validation and helper text

<Input
label="Password"
type="password"
error="Must be at least 8 characters"
/>

<Input
label="Name"
required
description="This will appear on your profile."
/>

Variants

Input does not have visual style variants (like primary/secondary). Instead, it focuses on state-based styling (error, disabled) and size variants.


Sizes

The input supports three size variants via the inputSize prop.

<Input inputSize="sm" label="Small input" />
<Input inputSize="md" label="Medium input" />
<Input inputSize="lg" label="Large input" />

Available sizes:

  • sm – Compact inputs for dense layouts
  • md (default) – Standard form usage
  • lg – Emphasized or primary form fields

States

Required

<Input label="Email" required />
  • Automatically appends * to the label.
  • Uses native required behavior.

Disabled

<Input label="Username" disabled />
  • Reduced opacity
  • Cursor disabled
  • Non-interactive

Error

<Input label="Password" type="password" error="Must be at least 8 characters" />
  • Red border and background
  • Error message announced via aria-describedby
  • aria-invalid="true" applied automatically

Native Props / Composition

Input extends all native <input> props via React.InputHTMLAttributes<HTMLInputElement>.

<Input
label="Search"
placeholder="Search..."
onChange={handleChange}
aria-label="Search input"
data-testid="search-input"
/>

Custom wrapper class

<Input label="Email" className="my-custom-wrapper" />

Props

PropTypeDefaultDescription
labelstringLabel displayed above the input
descriptionstringHelper text shown below the input (hidden when error exists)
errorstringError message and error styling
inputSize"sm" | "md" | "lg"mdControls padding and font size
idstringautoOverrides auto-generated ID
classNamestring""Custom wrapper class
...restInputHTMLAttributes<HTMLInputElement>All native input attributes

Behavior Notes

  • Automatically generates a stable ID using React.useId()

  • If id is passed, it overrides the auto-generated ID

  • aria-describedby dynamically switches between:

    • error message
    • helper description
  • Error message always takes priority over description

Example:

<Input
label="Username"
description="Publicly visible name"
error="Username already taken"
/>

Accessibility

  • Renders a native <input> with an associated <label>

  • Uses:

    • aria-invalid for error state
    • aria-describedby for error/description
  • WCAG-compliant contrast and focus indicators

  • :focus-visible used to avoid mouse focus noise

  • Fully keyboard accessible (Tab, Shift+Tab)


Layout

  • Block-level component
  • Always takes full width of its container
  • Wrapper uses column layout with consistent spacing
<div style={{ width: 250 }}>
<Input label="Email" />
</div>

Best Practices

Do

  • Always provide a label for accessibility
  • Use description for guidance, not validation
  • Use error only for actionable feedback
  • Let the input stretch to container width

Don’t

  • Use placeholder text as a label replacement
  • Show both description and error at the same time
  • Disable inputs without explaining why
  • Overuse lg size in dense forms