Components

Field

Headless single-control field wiring for labels, descriptions, errors, and shared form-control state.

When to Use

Use Field when one control needs a label and may also need help text, an error, or shared required/disabled state. Use Fieldset when several related controls need one group label, such as radio choices. Use standalone Label when no shared state or description/error wiring is needed.

Features

  • Generates stable control, label, description, and error IDs.
  • Shares disabled, required, read-only, and invalid state with Field-aware controls.
  • Registers mounted Description and visible Error IDs for aria-describedby.
  • Supports built-in or separately composed required/optional indicators.
  • Exposes layout orientation as metadata without applying layout.
  • Supports custom parts through public context hooks.

Import

import { Field } from "@flowstack-ui/atom";

Anatomy

<Field.Root>
  <Field.Label />
  <Field.Description />
  <Field.Error />
  <Field.RequiredIndicator />
</Field.Root>

useFieldContext()
useRequiredFieldContext()

API Reference

Root

Renders a div by default and provides generated relationships and shared state. It does not render the actual form control.

PropTypeDefault
disabledbooleanfalse
requiredbooleanfalse
readOnlybooleanfalse
invalidbooleanfalse
orientation"vertical" | "horizontal""vertical"
asChildbooleanfalse
renderRenderProp-

Supplying id creates ${id}-control, ${id}-label, ${id}-description, and ${id}-error; otherwise the base ID is generated.

Data attributeValues
[data-slot]"field"
[data-orientation]"vertical" | "horizontal"
[data-disabled]Present when disabled
[data-required]Present when required
[data-readonly]Present when read only
[data-invalid]Present when invalid

Label

Renders a native label whose htmlFor targets the generated control ID. State props can override Field state for this Label's metadata only.

PropTypeDefault
requiredbooleanField state
disabledbooleanField state
invalidbooleanField state
readOnlybooleanField state
requiredIndicatorReactNode" *"
optionalIndicatorReactNode-
asChildbooleanfalse
renderRenderProp-

Plain-text required indicators are wrapped with aria-hidden. Plain optional indicators remain available to assistive technology. A React element is used as provided.

Data attributeValues
[data-slot]"field-label"
[data-disabled]Present when resolved disabled
[data-required]Present when resolved required
[data-readonly]Present when resolved read only
[data-invalid]Present when resolved invalid

Description

Renders a p and registers its generated ID while mounted so Field-aware controls can include it in aria-describedby.

PropTypeDefault
asChildbooleanfalse
renderRenderProp-
Data attributeValues
[data-slot]"field-description"

Error

Renders a live alert only when Field is invalid and match is not false, or when forceMatch is true. A visible Error registers for aria-describedby.

PropTypeDefault
matchboolean-
forceMatchbooleanfalse
asChildbooleanfalse
renderRenderProp-
ARIA attributeValues
role"alert" while rendered
Data attributeValues
[data-slot]"field-error"

RequiredIndicator

Renders children for a required Field or fallback otherwise. Use it when the indicator should be a separate part; set Label's requiredIndicator={null} to avoid showing two required markers.

PropTypeDefault
childrenReactNode" *"
fallbackReactNode-
asChildbooleanfalse
renderRenderProp-
ARIA attributeValues
aria-hidden"true" for required content
Data attributeValues
[data-slot]"field-required-indicator" | "field-optional-indicator"

useFieldContext

Returns Field state and generated relationships, or null outside Root.

useRequiredFieldContext

Returns the same context but throws when used outside Root. Use it for a custom part that cannot function without Field.

Examples

Email With Help and Error

import { useState } from "react";
import { Field, Input } from "@flowstack-ui/atom";

export function EmailField() {
  const [email, setEmail] = useState("");
  const invalid = email.length > 0 && !email.includes("@");

  return (
    <Field.Root id="email" required invalid={invalid}>
      <Field.Label>Email</Field.Label>
      <Input.Root name="email" value={email} onValueChange={setEmail} />
      <Field.Description>Use an address you check regularly.</Field.Description>
      <Field.Error>Enter a valid email address.</Field.Error>
    </Field.Root>
  );
}

Explicit Optional Indicator

import { Field, Input } from "@flowstack-ui/atom";

export function NicknameField() {
  return (
    <Field.Root id="nickname">
      <Field.Label requiredIndicator={null}>
        Nickname <Field.RequiredIndicator fallback="(optional)" />
      </Field.Label>
      <Input.Root name="nickname" />
    </Field.Root>
  );
}

Accessibility

Field follows native form labeling and the WAI forms labeling guidance. Field-aware controls use Label's ID relationship and include mounted Description and visible Error IDs in aria-describedby. Error uses role="alert"; do not use invalid state before there is a useful message for the user. Field owns no keyboard behavior.

Changelog

See CHANGELOG.md.