Field

Connects a form control with its label, description, hint and error, so they are all linked for you.

We only use it to send invoices.

import {
  Field,
  FieldControl,

When to use it

Wrap a form control in a Field whenever it has a label. The field links the pieces together for assistive technology: the label names the control, the description and hint are read after it, and an error is announced when it appears. You write none of the id, htmlFor and aria-describedby wiring yourself.

Most inputs in this library work inside a Field, such as the Combobox, the Date Picker and the OTP Field. To group several fields under one heading, use a Form Section.

Import

import {
  Field,
  FieldLabel,
  FieldDescription,
  FieldControl,
  FieldHelperText,
  FieldError,
  FieldGroup,
  FieldGroupAddon,
} from "@hel/ui/field"

The parts

Field is a set of small parts that you put together, so you decide which ones a field needs and in what order.

PartWhat it is for
FieldThe wrapper. Takes invalid and disabled and passes them to every part inside.
FieldLabelThe label. required adds an asterisk, and icon adds a small help icon after it.
FieldDescriptionText about the field, such as what the value is used for.
FieldControlA text input. Takes every prop of an input, such as type, placeholder and defaultValue.
FieldHelperTextA line under the control, for guidance such as a format or a limit.
FieldErrorThe error message.
FieldGroup, FieldGroupAddonA box that joins a control to an addon, such as a URL prefix.

The order is yours. A common one puts the description between the label and the control, and the helper text under the control. Use the description for what the field is for, and the helper text for what to type.

Examples

Hints and notes

FieldHelperText has three tones. The default, neutral, is plain guidance that turns red when the field is invalid, so the same line works for "At least 3 characters" before and after a mistake. warning and info are notes that never block: they keep their own color whatever state the field is in.

At least 3 characters.

At least 3 characters.

Usually due within 90 days.

It is printed on the invoice.

import { Field, FieldControl, FieldHelperText, FieldLabel } from "@hel/ui/field"
import { Stack } from "@hel/ui/stack"

Showing errors

Set invalid on the field to mark it, and render a FieldError with the message. Showing it is up to you, which means you can drive it from your own rules, a form library or the server. In this demo the message appears while the address is not valid. If you use a Form, it fills in errors from the server for you.

Enter an email address, such as name@example.com.
import * as React from "react"

import { Field, FieldControl, FieldError, FieldLabel } from "@hel/ui/field"

A FieldError also takes match, such as "valueMissing", to show only for one of the browser's own checks.

Joining an addon to the control

FieldGroup draws one box around a FieldControl and its addons. A FieldGroupAddon can hold text, a keyboard shortcut or an icon through leadingIcon and trailingIcon. It goes before the control for a prefix and after it for a suffix.

https://
⌘K
import { Mail } from "lucide-react"

import {

Other states

disabled on the Field turns off the control and dims the label and the text around it. FieldLabel takes required for the asterisk, but it doesn't make the control required, so set required on the control too when the browser or a form should enforce it.

Props

Field

PropTypeDefault
invalidbooleanfalse
disabledbooleanfalse
namestring, to match a server error in a Formnone

It takes every prop of the Base UI field.

FieldLabel

PropTypeDefault
requiredboolean, shows an asteriskfalse
iconboolean, shows a help iconfalse

FieldHelperText

PropTypeDefault
tone"neutral" | "warning" | "info""neutral"

FieldError

PropTypeDefault
matchtrue or a validity key such as "valueMissing"true

FieldGroupAddon

PropTypeDefault
leadingIconAn icon component, such as LucideIconnone
trailingIconAn icon component, such as LucideIconnone