Field

Wires a label, a control, help text and an error message together — id, aria-describedby and aria-invalid, all of which are easy to get one short of by hand.

src/components/ui/field.tsx

About

From the component's own source, where it was written.

Wires a label, a control, help text and an error message together.

The plumbing is the point: the control gets an id, aria-describedby pointing at whichever of description and error is present, and aria-invalid when there is an error. Done by hand at every call site, one of those is always missing.

Deliberately not tied to a form library — it describes one field's accessibility, and works the same whether state comes from useState, React Hook Form or a server action.

Install

npx astralyx-ui add field

Usage

import { Field, FieldLabel } from '@/components/ui/field'

function EmailField({ error }) {
  return (
    <Field error={error} description="We only use this for receipts.">
      <FieldLabel required>Email</FieldLabel>
      <Input {...useFieldControl()} type="email" />
    </Field>
  )
}

Composer

Change the props and the source below follows.

We only use this for receipts.

Props
tsx
<Field
  description="We only use this for receipts."
>
  <FieldLabel required>Email</FieldLabel>
  <Input {...useFieldControl()} type="email" />
</Field>

Examples

Valid and invalid

API

Generated from the source, so it cannot fall behind the code. One table per exported component, then hooks, functions and types.

Field

Extends ComponentProps<'div'>.

PropTypeDefaultDescription
errorReactNode—Message under the control. Its presence is what marks the field invalid — there is no separate flag to keep in sync.
descriptionReactNode—Help text. Hidden while an error is showing, so the two never stack.

FieldLabel

A Label with htmlFor already pointed at the control.

Extends ComponentProps<typeof Label>.

PropTypeDefaultDescription
requiredboolean——

Hooks

HookSignatureDescription
useFieldControl() => { id: string; 'aria-describedby': string; 'aria-invalid': true; }Spread onto any control: returns id, aria-describedby and aria-invalid. Works with controls this kit does not own.