Experience System
Components

Field

Layout primitives for labels, descriptions, errors, and grouped form regions.

This name appears on your profile and invoices.

Installation

The components are exported from @by/experience-system. Add the package with your package manager:

pnpm add @by/experience-system

In this monorepo, depend on the workspace package (for example via workspace:* or your catalog) so imports resolve to packages/experience-system.

Composition

Use the following composition for form fields and grouped sections:

FieldGroup
├── FieldSet (optional)
│   ├── FieldLegend (optional)
│   ├── FieldDescription (optional)
│   └── FieldGroup (nested)
│       └── Field
│           ├── FieldLabel
│           ├── FieldContent (optional)
│           ├── (control: Input, Select, Checkbox, …)
│           ├── FieldDescription (optional)
│           └── FieldError (optional)
├── FieldSeparator (optional)
└── FieldTitle (optional, section heading style)

Field sets role="group" and supports orientation for label/control layout. FieldError renders role="alert" when content is present.

Usage

import {
  Field,
  FieldDescription,
  FieldError,
  FieldGroup,
  FieldLabel,
} from '@by/experience-system';

Field and its parts are client components ('use client'). Use them inside a Client Component or a dynamic import when using the Next.js App Router.

<Field>
  <FieldLabel htmlFor="email">Email</FieldLabel>
  <Input id="email" type="email" />
  <FieldDescription>We will never share your email.</FieldDescription>
</Field>

Examples

Overview

Label, control, and description in a vertical Field.

This name appears on your profile and invoices.

Checkout-style form

FieldSet, FieldLegend, nested FieldGroup, FieldSeparator, and horizontal Field rows.

Payment Method

All transactions are secure and encrypted

Enter your 16-digit card number

Billing Address

The billing address associated with your payment method

Horizontal field

orientation="horizontal" for checkbox or compact label/control rows.

Invalid state

data-invalid on Field with FieldError and aria-invalid on the control.

API Reference

Subsection titles name the exports from @by/experience-system. These are layout and typography wrappers (not Radix primitives).

Field

PropTypeDefault
orientationvertical | horizontal | responsivevertical
Data attributeValues
data-slotfield
data-orientationmirrors orientation

Renders role="group". Also accepts standard div attributes.

FieldLabel

Forwards to the Experience System Label with field spacing and nested Field affordances.

Data attributeValues
data-slotfield-label

Also accepts Label props (for example htmlFor).

FieldTitle

Non-label title row inside a field group.

Data attributeValues
data-slotfield-label

Also accepts standard div attributes.

FieldDescription

Supporting copy; link styles apply to anchors inside.

Data attributeValues
data-slotfield-description

Also accepts standard p attributes.

FieldError

PropTypeDefault
errorsArray<{ message?: string } | undefined>
Data attributeValues
data-slotfield-error

Renders role="alert" when children or resolved errors produce content; otherwise returns null. Also accepts standard div attributes.

FieldGroup

Data attributeValues
data-slotfield-group

Also accepts standard div attributes.

FieldSet

Data attributeValues
data-slotfield-set

Also accepts standard fieldset attributes.

FieldLegend

PropTypeDefault
variantlegend | labellegend
Data attributeValues
data-slotfield-legend
data-variantmirrors variant

Also accepts standard legend attributes.

FieldSeparator

Optional inline label between groups; renders a Separator with optional centered text.

PropTypeDefault
childrenReact.ReactNode
Data attributeValues
data-slotfield-separator
data-contenttrue when children is present

Also accepts standard div attributes.

FieldContent

Stacks helper text tightly around a control.

Data attributeValues
data-slotfield-content

Also accepts standard div attributes.

Accessibility

Associate FieldLabel with controls via htmlFor / id. Surface errors with FieldError and aria-invalid on inputs so the role="alert" message is read after the control name. Use FieldSet + FieldLegend for groups of related inputs. See MDN — Labels and your product form guidelines.

Source in the repo: packages/experience-system/src/components/Field/Field.tsx. Agent-oriented contracts: packages/experience-system/src/components/Field/Field.instructions.md.