moduix

Field

A composable wrapper that labels, describes, and validates form controls.

API Reference

Original primitive API

Behavior, accessibility details, and low-level props are documented by Base UI.

Base UI API

Basic

Visible on your public profile.

import {  Field,  FieldControl,  FieldDescription,  FieldError,  FieldLabel,} from "moduix";export function FieldDemo() {  return (    <Field validationMode="onBlur">      <FieldLabel>Name</FieldLabel>      <FieldControl required placeholder="Enter your name" />      <FieldError match="valueMissing">Please enter your name.</FieldError>      <FieldDescription>Visible on your public profile.</FieldDescription>    </Field>  );}

Full list of component variables available for project-level overrides.

PropertyDefaultDescription
--field-colorvar(--color-foreground)Controls inherited field text color.
--field-control-bgvar(--color-background)Controls `FieldControl` background.
--field-control-border-colorvar(--color-border)Controls `FieldControl` border color.
--field-control-border-color-invalidvar(--color-destructive)Controls invalid `FieldControl` border and focus ring color.
--field-control-border-stylesolidControls `FieldControl` border style.
--field-control-border-widthvar(--border-width-sm)Controls `FieldControl` border width.
--field-control-colorvar(--color-foreground)Controls `FieldControl` text color.
--field-control-font-sizevar(--text-md)Controls `FieldControl` font size.
--field-control-heightvar(--size-lg)Controls `FieldControl` minimum height.
--field-control-line-heightvar(--line-height-text-md)Controls `FieldControl` line height.
--field-control-padding-x0.875remControls `FieldControl` horizontal padding.
--field-control-padding-y0.5remControls `FieldControl` vertical padding.
--field-control-placeholder-colorvar(--color-muted-foreground)Controls `FieldControl` placeholder color.
--field-control-radiusvar(--radius-md)Controls `FieldControl` corner radius.
--field-control-transitionvar(--transition-default)Controls `FieldControl` state transition timing.
--field-control-width100%Controls `FieldControl` width.
--field-description-colorvar(--color-muted-foreground)Controls description text color.
--field-description-font-sizevar(--text-sm)Controls description font size.
--field-description-line-heightvar(--line-height-text-sm)Controls description line height.
--field-disabled-opacityvar(--opacity-disabled)Controls disabled slot opacity.
--field-error-colorvar(--color-destructive)Controls error text color.
--field-error-font-sizevar(--text-sm)Controls error font size.
--field-error-line-heightvar(--line-height-text-sm)Controls error line height.
--field-focus-ring-colorvar(--color-ring)Controls `FieldControl` focus ring color.
--field-focus-ring-offset-1pxControls `FieldControl` focus ring offset.
--field-focus-ring-widthvar(--border-width-sm)Controls `FieldControl` focus ring width.
--field-gapvar(--spacing-1)Controls spacing between field parts.
--field-item-gapvar(--spacing-1)Controls spacing inside `FieldItem`.
--field-label-colorvar(--color-foreground)Controls label text color.
--field-label-font-sizevar(--text-sm)Controls label font size.
--field-label-font-weightvar(--weight-medium)Controls label font weight.
--field-label-gapvar(--spacing-2)Controls spacing inside `FieldLabel`.
--field-label-line-heightvar(--line-height-text-sm)Controls label line height.
--field-max-widthnoneControls the root field max width.
--field-width100%Controls the root field width.

Interactive variables scoped for docs preview without changing size scale tokens.

PropertyValueDefaultDescription
--field-control-bgvar(--color-background)Controls control background.
--field-control-border-colorvar(--color-border)Controls control border color.
--field-control-colorvar(--color-foreground)Controls control text color.
--field-control-radiusvar(--radius-md)Controls control radius.
--field-description-colorvar(--color-muted-foreground)Controls description color.
--field-error-colorvar(--color-destructive)Controls error text color.
--field-focus-ring-colorvar(--color-ring)Controls focus ring color.
--field-gapvar(--spacing-1)Controls spacing between field parts.
--field-label-colorvar(--color-foreground)Controls label text color.

Anatomy

Field acts as a semantic wrapper around one form control and its helper text. Keep label, control, error, and description inside the same Field so IDs, validation state, and ARIA links stay synchronized.

Field
├─ FieldLabel
│  └─ label content / optional control composition
├─ FieldControl (or another compatible control, for example Input)
├─ FieldError[match]
└─ FieldDescription
<Field validationMode="onBlur">
  <FieldLabel>Email</FieldLabel>
  <FieldControl required type="email" placeholder="name@example.com" />
  <FieldError match="valueMissing">Please enter your email.</FieldError>
  <FieldError match="typeMismatch">Enter a valid email address.</FieldError>
  <FieldDescription>We will only use this for account notifications.</FieldDescription>
</Field>
PartRole
FieldRoot context. Coordinates validation mode, disabled state, naming, and slot relationships.
FieldLabelAccessible label for the field control. Can wrap composed controls like Switch or Checkbox.
FieldControlDefault text-like control slot that receives invalid/disabled styling hooks.
FieldErrorValidation message slot filtered by match (for example valueMissing, customError).
FieldDescriptionSupplemental helper text linked to the control for assistive technologies.
FieldItemOptional layout wrapper for grouped rows inside the same field, such as radio options.

Field does not have service slots such as portal, backdrop, or viewport. In most cases, keep default structure and style only visible slots (FieldLabel, FieldControl, FieldError, FieldDescription, and optional FieldItem) via className and CSS variables.

Composition

Use Field for root behavior and validation props such as name, validationMode, validationDebounceTime, validate, actionsRef, invalid, dirty, touched, and disabled.

Compose FieldLabel, one compatible control (FieldControl, Input, NumberField, and others), then optional FieldError and FieldDescription. Customize each visible slot through className. All Base UI parts also support render, function className, function style, and state data attributes such as data-invalid, data-valid, data-dirty, data-touched, data-filled, data-focused, and data-disabled.

Use FieldControl for a default native input, or omit it and place another Base UI-compatible control in the field. FieldLabel supports nativeLabel={false} when the label is rendered as a non-label element for controls such as select or combobox triggers. FieldError match accepts true or a ValidityState key such as valueMissing, typeMismatch, or customError; FieldValidity exposes the full validity object through a render function.

The package exports Base UI helper types for advanced composition:

import {
  type FieldActions,
  type FieldState,
  type FieldControlChangeEventDetails,
  type FieldValidityState,
} from 'moduix';

Examples

Custom Validation

Use validate for rules that are not covered by native input validity.

Waiting for valid value.

import {  Field,  FieldControl,  FieldError,  FieldLabel,  FieldValidity,} from "moduix";export function CustomValidationFieldDemo() {  return (    <Field      validationMode="onChange"      validate={(value) => {        if (typeof value !== "string" || value.length < 3) {          return "Username must be at least 3 characters.";        }        return null;      }}    >      <FieldLabel>Username</FieldLabel>      <FieldControl placeholder="e.g. Vinny" />      <FieldError match="customError" />      <FieldValidity>        {(state) => (          <p className={styles.helper}>            {state.validity.valid ? "Looks good." : "Waiting for valid value."}          </p>        )}      </FieldValidity>    </Field>  );}
.helper {  margin: 0;  color: var(--color-muted-foreground);  font-size: var(--text-sm);  line-height: var(--line-height-text-sm);}

Disabled

Set disabled on the root to disable the whole field and propagate the disabled state to supported controls.

This field is currently managed by your workspace.

import {  Field,  FieldControl,  FieldDescription,  FieldLabel,} from "moduix";export function DisabledFieldDemo() {  return (    <Field disabled>      <FieldLabel>Organization</FieldLabel>      <FieldControl placeholder="Acme Inc." />      <FieldDescription>        This field is currently managed by your workspace.      </FieldDescription>    </Field>  );}

Checkbox

Wrap checkbox controls in Field when the checkbox needs validation, description, or form naming.

Required to continue.

import {  Field,  Checkbox,  CheckboxIndicator,  FieldDescription,  FieldError,  FieldLabel,} from "moduix";export function CheckboxFieldDemo() {  return (    <Field validationMode="onBlur">      <FieldLabel>        <Checkbox required name="terms">          <CheckboxIndicator />        </Checkbox>        I agree to the terms      </FieldLabel>      <FieldError match="valueMissing">Please accept the terms.</FieldError>      <FieldDescription>Required to continue.</FieldDescription>    </Field>  );}

Radio

Use FieldItem to group individual radio rows while keeping each slot available for styling.

import {  Field,  FieldError,  FieldItem,  FieldLabel,  Radio,  RadioField,  RadioGroup,  RadioLabel,} from "moduix";export function RadioFieldDemo() {  return (    <Field name="account-type" validationMode="onBlur">      <FieldLabel>Account type</FieldLabel>      <RadioGroup>        <FieldItem>          <RadioField>            <Radio value="personal" required />            <RadioLabel>Personal account</RadioLabel>          </RadioField>        </FieldItem>        <FieldItem>          <RadioField>            <Radio value="team" />            <RadioLabel>Team account</RadioLabel>          </RadioField>        </FieldItem>      </RadioGroup>      <FieldError match="valueMissing">        Please choose an account type.      </FieldError>    </Field>  );}

Switch

Compose FieldLabel with switch controls when the label should activate the control.

We send updates once per week.

import {  Field,  FieldDescription,  FieldLabel,  Switch,  SwitchLabel,} from "moduix";export function SwitchFieldDemo() {  return (    <Field name="newsletter">      <FieldLabel>        <Switch />        <SwitchLabel>Subscribe to newsletter</SwitchLabel>      </FieldLabel>      <FieldDescription>We send updates once per week.</FieldDescription>    </Field>  );}

Input

Use any Base UI-compatible input component inside Field; Input works with labels and validation out of the box.

import { Field, FieldLabel, Input, FieldError } from "moduix";export function InputFieldDemo() {  return (    <Field validationMode="onBlur">      <FieldLabel>Email</FieldLabel>      <Input required type="email" placeholder="name@example.com" />      <FieldError match="valueMissing">Please enter your email.</FieldError>      <FieldError match="typeMismatch">Enter a valid email address.</FieldError>    </Field>  );}

Number Field

Pair Field with compound controls by linking the label with the control id.

import {  Field,  FieldError,  NumberField,  NumberFieldDecrement,  NumberFieldGroup,  NumberFieldInput,  NumberFieldIncrement,  FieldLabel,} from "moduix";import { useId } from "react";export function NumberFieldDemo() {  const id = useId();  return (    <Field name="quantity" validationMode="onBlur">      <FieldLabel htmlFor={id}>Items</FieldLabel>      <NumberField id={id} min={1} max={10} required>        <NumberFieldGroup>          <NumberFieldDecrement aria-label="Decrease value" />          <NumberFieldInput />          <NumberFieldIncrement aria-label="Increase value" />        </NumberFieldGroup>      </NumberField>      <FieldError match="valueMissing">Please provide a number.</FieldError>      <FieldError match="rangeUnderflow">Value should be at least 1.</FieldError>      <FieldError match="rangeOverflow">Value should be at most 10.</FieldError>    </Field>  );}

Custom Styles

Pass className to every visible slot when styling the field with CSS Modules.

Use three to five uppercase letters.

import {  Field,  FieldControl,  FieldDescription,  FieldError,  FieldLabel,} from "moduix";export function CustomStylesFieldDemo() {  return (    <Field validationMode="onBlur" className={styles.customField}>      <FieldLabel className={styles.customLabel}>Project key</FieldLabel>      <FieldControl        required        placeholder="MAPS"        className={styles.customControl}      />      <FieldDescription className={styles.customDescription}>        Use three to five uppercase letters.      </FieldDescription>      <FieldError className={styles.customError} match="valueMissing">        Please enter a project key.      </FieldError>    </Field>  );}
.customField {  width: min(22rem, 100%);  max-width: 20rem;  gap: var(--spacing-2);}.customLabel,.customError {  color: var(--color-primary);}.customControl {  border-color: color-mix(in srgb, var(--color-primary) 40%, transparent);}.customControl:focus {  outline-color: var(--color-primary);}.customDescription {  color: var(--color-muted-foreground);}

On this page