Form

Field

Label, description and error around one control. It wires `id`, `aria-describedby`, `aria-invalid` and `aria-required` into the control, so every input in a form is announced correctly.

Shown in the sidebar and in invites.

Usage

  • Do wrap every form control in a Field: it is the only way to get the label, description and error wired correctly.
  • Do write errors that say how to fix the value ("Enter an email like name@company.com"), not just "Invalid".
  • Do show errors after the person leaves the field or submits, not on every keystroke.
  • Don’t use the placeholder as the label; use hideLabel only when the purpose is obvious.
  • Don’t put several controls in one Field; for a group of checkboxes use a fieldset with a legend.
  • What works as the child: any Motion form control (TextInput, Textarea, SearchInput, NumberInput, Select, Combobox, Checkbox, Switch, RadioGroup, Slider, SegmentedControl, Calendar, DatePicker, DateRangePicker, FileUpload) or a native input / select / textarea, directly or inside a wrapper <div>; the label finds it.
  • Don’t put a Menu (or a Popover with buttons) in a Field to pick a value: menus are for actions. Use Select for a short list and Combobox for a long or searchable one.
  • For a custom control, pass htmlFor and give your control the same id (or build it with useFieldProps). In development, Field warns in the console when its label names no control.

Installation

Install the package (React 19):

terminal
npm install @krackedui/motion

Import the styles once, in your app entry or root layout:

/src/main.tsx
import '@krackedui/motion/styles.css';

Use it anywhere inside your app's <Theme> (see Installation):

/src/FieldExample.tsx
import { Field, TextInput } from '@krackedui/motion';

export function WorkspaceNameField() {
  return (
    <Field label="Workspace name" description="Shown in the sidebar and in invites.">
      <TextInput defaultValue="Design Team" />
    </Field>
  );
}

Examples

Error

Passing error marks the control invalid (red ring, aria-invalid) and adds the message to its description. The message is announced politely when it appears.

We send the invite here.

Enter an email like name@company.com.

Any control

Every control in the package reads the Field. Other elements (a plain <input>, a third-party control) get the same props cloned in.

Billed monthly.

Hidden label

hideLabel keeps the label as the accessible name but hides it visually; use it only when the purpose is obvious from context.

Disabled

Contact an owner to change it.

Dark theme

Name is required.

API Reference

Field

A <div> (all its props are passed through). Adds:

PropTypeDefault
label
ReactNode
description
ReactNode
error
ReactNode
required
boolean
false
hideLabel
boolean
false
disabled
boolean
false
htmlFor
string
children
ReactNode

Helpers

For building your own controls that work inside a Field.

PropTypeDefault
useFieldProps(props)
(props) => props
useFieldControl()
FieldContextValue | null
fieldVariants
tv recipe

Accessibility

  • The <label> points at the control (htmlFor); controls that aren’t labelable (slider thumbs, radio groups, date triggers) use aria-labelledby with the label id instead.
  • Description and error are linked with aria-describedby, in that order; the error id is only included while there is an error.
  • The error sits in an aria-live="polite" region, so it is announced when it appears, without stealing focus.
  • The required asterisk is aria-hidden; the control carries aria-required instead.
© 2026 Motion. Internal documentation.