gnome-ui
Components

Field

A set of components to build accessible form fields with labels, descriptions, and validation messages.

Field component

We'll use this email to send you system notifications.

import * as React from 'react';
import { Field } from 'gnome-ui/field';
import { Input } from 'gnome-ui/input';

export function FieldDefault() {
  return (
    <Field.Root className="flex w-full max-w-sm flex-col gap-2">
      <Field.Label className="text-sm font-medium text-foreground">
        Email
      </Field.Label>
      <Field.Control >
        <Input 
          className="flex h-10 w-full rounded-xl border border-input bg-card px-3 py-2 text-sm text-foreground shadow-sm transition-colors focus-visible:border-primary focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring disabled:cursor-not-allowed disabled:opacity-50 data-[invalid]:border-destructive data-[invalid]:focus-visible:outline-destructive" 
          placeholder="you@example.com" 
          type="email" 
        />
      </Field.Control>
      <Field.Description className="text-xs text-muted-foreground">
        We'll use this email to send you system notifications.
      </Field.Description>
    </Field.Root>
  );
}

Anatomy

import { Field } from 'gnome-ui/field';

<Field.Root>
  <Field.Label />
  <Field.Control />
  <Field.Description />
  <Field.Error>
    <Field.Validity />
  </Field.Error>
</Field.Root>

Examples

With Validation Error

The Field component handles form validation automatically. It manages the validity state and shows the Field.Error component when the validation fails. Try submitting the form below with an empty or short value.

Field component
import * as React from 'react';
import { Field } from 'gnome-ui/field';
import { Input } from 'gnome-ui/input';
import { AlertCircle } from 'lucide-react';

export function FieldWithError() {
  return (
    <form 
      onSubmit={(e) => {
        e.preventDefault();
        // Form submission logic
      }}
      className="w-full max-w-sm"
    >
      <Field.Root 
        className="flex w-full flex-col gap-2" 
        validate={(value) => {
          if (!value) return 'Username is required.';
          if (String(value).length < 4) return 'Must have at least 4 characters.';
          return null;
        }}
      >
        <Field.Label className="text-sm font-medium text-foreground">
          Username
        </Field.Label>
        <Field.Control >
          <Input 
            className="flex h-10 w-full rounded-xl border border-input bg-card px-3 py-2 text-sm text-foreground shadow-sm transition-colors focus-visible:border-primary focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring disabled:cursor-not-allowed disabled:opacity-50 data-[invalid]:border-destructive data-[invalid]:focus-visible:outline-destructive" 
            placeholder="Ej: ubuntu_user" 
          />
        </Field.Control>
        
        <Field.Error className="flex items-center gap-1.5 text-sm font-medium text-destructive">
          <Icons.AlertCircle className="size-4 shrink-0" />
          <Field.Validity>
            {(state) => state.error || 'Invalid input'}
          </Field.Validity>
        </Field.Error>
        
        <button 
          type="submit" 
          className="mt-2 inline-flex h-9 items-center justify-center rounded-xl bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:brightness-95 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring active:brightness-90"
        >
          Save
        </button>
      </Field.Root>
    </form>
  );
}

FieldControl

The form control to label and validate. Renders an &lt;input&gt; element.

You can omit this part and use any Base UI input component instead. For example, Input, Checkbox, or Select, among others, will work with Field out of the box.

Documentation: Base UI Field

API reference

Root

Groups all parts of the field. Renders a <div> element.

Root Props:

PropTypeDefaultDescription
namestring-Identifies the field when a form is submitted. Takes precedence over the name prop on the <Field.Control> component.
actionsRefRefObject<Field.Root.Actions | null>-A ref to imperative actions.* validate: Validates the field when called.
dirtyboolean-Whether the field's value has been changed from its initial value. Useful when the field state is controlled by an external library.
touchedboolean-Whether the field has been touched. Useful when the field state is controlled by an external library.
disabledbooleanfalseWhether the component should ignore user interaction. Takes precedence over the disabled prop on the <Field.Control> component.
invalidboolean-Whether the field is invalid. Useful when the field state is controlled by an external library.
validate((value: unknown, formValues: Form.Values<string, any>) => string | string[] | Promise<string | string[] | null> | null)-A function for custom validation. Return a string or an array of strings with the error message(s) if the value is invalid, or null if the value is valid. Asynchronous functions are supported, but they do not prevent form submission when using validationMode="onSubmit".
validationModeForm.ValidationMode'onSubmit'Determines when the field should be validated. This takes precedence over the validationMode prop on <Form>.* onSubmit: triggers validation when the form is submitted, and re-validates on change after submission.
  • onBlur: triggers validation when the control loses focus.
  • onChange: triggers validation on every change to the control value. | | validationDebounceTime | number | 0 | How long to wait between validate callbacks if validationMode="onChange" is used. Specified in milliseconds. | | className | string \| ((state: Field.Root.State) => string \| undefined) | - | CSS class applied to the element, or a function that returns a class based on the component’s state. | | style | CSSProperties \| ((state: Field.Root.State) => CSSProperties \| undefined) | - | - | | render | ReactElement \| ((props: HTMLProps, state: Field.Root.State) => ReactElement) | - | Allows you to replace the component’s HTML element with a different tag, or compose it with another component.Accepts a ReactElement or a function that returns the element to render. |

Root Data Attributes:

AttributeTypeDescription
data-disabled-Present when the field is disabled.
data-valid-Present when the field is valid.
data-invalid-Present when the field is invalid.
data-dirty-Present when the field's value has changed.
data-touched-Present when the field has been touched.
data-filled-Present when the field is filled.
data-focused-Present when the field control is focused.

Label

An accessible label that is automatically associated with the field control. Renders a <label> element.

Label Props:

PropTypeDefaultDescription
nativeLabelbooleantrueWhether the component renders a native <label> element when replacing it via the render prop. Set to false if the rendered element is not a label (e.g. <div>).This is useful to avoid inheriting label behaviors on <button> controls (such as <Select.Trigger> and <Combobox.Trigger>), including avoiding :hover on the button when hovering the label, and preventing clicks on the label from firing on the button.
classNamestring | ((state: Field.Root.State) => string | undefined)-CSS class applied to the element, or a function that returns a class based on the component’s state.
styleCSSProperties | ((state: Field.Root.State) => CSSProperties | undefined)--
renderReactElement | ((props: HTMLProps, state: Field.Root.State) => ReactElement)-Allows you to replace the component’s HTML element with a different tag, or compose it with another component.Accepts a ReactElement or a function that returns the element to render.

Label Data Attributes:

AttributeTypeDescription
data-disabled-Present when the field is disabled.
data-valid-Present when the field is in valid state.
data-invalid-Present when the field is in invalid state.
data-dirty-Present when the field's value has changed.
data-touched-Present when the field has been touched.
data-filled-Present when the field is filled.
data-focused-Present when the field control is focused.

Control

The form control to label and validate. Renders an <input> element.You can omit this part and use any Base UI input component instead. For example, Input, Checkbox, or Select, among others, will work with Field out of the box.

Control Props:

PropTypeDefaultDescription
defaultValuestring | number | string[]--
onValueChange((value: string, eventDetails: Field.Control.ChangeEventDetails) => void)-Callback fired when the value changes. Use when controlled.
classNamestring | ((state: Field.Root.State) => string | undefined)-CSS class applied to the element, or a function that returns a class based on the component’s state.
styleCSSProperties | ((state: Field.Root.State) => CSSProperties | undefined)-*
renderReactElement | ((props: HTMLProps, state: Field.Root.State) => ReactElement)-Allows you to replace the component’s HTML element with a different tag, or compose it with another component.Accepts a ReactElement or a function that returns the element to render.

Control Data Attributes:

AttributeTypeDescription
data-disabled-Present when the field is disabled.
data-valid-Present when the field is in valid state.
data-invalid-Present when the field is in invalid state.
data-dirty-Present when the field's value has changed.
data-touched-Present when the field has been touched.
data-filled-Present when the field is filled.
data-focused-Present when the field control is focused.

Description

A paragraph with additional information about the field. Renders a <p> element.

Description Props:

PropTypeDefaultDescription
classNamestring | ((state: Field.Root.State) => string | undefined)-CSS class applied to the element, or a function that returns a class based on the component’s state.
styleCSSProperties | ((state: Field.Root.State) => CSSProperties | undefined)--
renderReactElement | ((props: HTMLProps, state: Field.Root.State) => ReactElement)-Allows you to replace the component’s HTML element with a different tag, or compose it with another component.Accepts a ReactElement or a function that returns the element to render.

Description Data Attributes:

AttributeTypeDescription
data-disabled-Present when the field is disabled.
data-valid-Present when the field is in valid state.
data-invalid-Present when the field is in invalid state.
data-dirty-Present when the field's value has changed.
data-touched-Present when the field has been touched.
data-filled-Present when the field is filled.
data-focused-Present when the field control is focused.

Item

Groups individual items in a checkbox group or radio group with a label and description. Renders a <div> element.

Item Props:

PropTypeDefaultDescription
disabledbooleanfalseWhether the wrapped control should ignore user interaction. The disabled prop on <Field.Root> takes precedence over this.
classNamestring | ((state: Field.Root.State) => string | undefined)-CSS class applied to the element, or a function that returns a class based on the component’s state.
styleCSSProperties | ((state: Field.Root.State) => CSSProperties | undefined)--
renderReactElement | ((props: HTMLProps, state: Field.Root.State) => ReactElement)-Allows you to replace the component’s HTML element with a different tag, or compose it with another component.Accepts a ReactElement or a function that returns the element to render.

Error

An error message displayed if the field control fails validation. Renders a <div> element.

Error Props:

PropTypeDefaultDescription
matchboolean | 'valid' | 'badInput' | 'customError' | 'patternMismatch' | 'rangeOverflow' | 'rangeUnderflow' | 'stepMismatch' | 'tooLong' | 'tooShort' | 'typeMismatch' | 'valueMissing'-Determines whether to show the error message according to the field’s ValidityState. Specifying true will always show the error message, and lets external libraries control the visibility.
classNamestring | ((state: Field.Error.State) => string | undefined)-CSS class applied to the element, or a function that returns a class based on the component’s state.
styleCSSProperties | ((state: Field.Error.State) => CSSProperties | undefined)--
renderReactElement | ((props: HTMLProps, state: Field.Error.State) => ReactElement)-Allows you to replace the component’s HTML element with a different tag, or compose it with another component.Accepts a ReactElement or a function that returns the element to render.

Error Data Attributes:

AttributeTypeDescription
data-disabled-Present when the field is disabled.
data-valid-Present when the field is in valid state.
data-invalid-Present when the field is in invalid state.
data-dirty-Present when the field's value has changed.
data-touched-Present when the field has been touched.
data-filled-Present when the field is filled.
data-focused-Present when the field control is focused.

Validity

Used to display a custom message based on the field’s validity. Requires children to be a function that accepts field validity state as an argument.

Validity Props:

PropTypeDefaultDescription
children((state: Field.Validity.State) => ReactNode)-A function that accepts the field validity state as an argument.```jsx

On this page