All components
Field
Label, control, helper text, and error slots with vertical and horizontal orientations.
We never share your email.
123456789101112131415161718192021import * as stylex from "@stylexjs/stylex";import { Field } from "#components/ui/ark-ui/field.tsx";import { inputSizes, inputStyles, inputVariants } from "@stylexblocks/ui/recipes/input.ts";
export function Example() { return ( // Root wires label/control/helper-text ids and state; the orientation // prop switches between stacked and two-column layouts <Field.Root required orientation="vertical"> <Field.Label> Email <Field.RequiredIndicator /> </Field.Label> <Field.Input placeholder="you@company.com" {...stylex.props(inputStyles.base, inputSizes.md, inputVariants.outline)} /> <Field.HelperText>We never share your email.</Field.HelperText> </Field.Root> );}Variants
We never share your email.
verticalWe never share your email.
horizontalInstall
1npx stylexblocks add fieldSource
components/ui/ark-ui/field.tsx
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136import * as stylex from "@stylexjs/stylex";import { Field as ArkField } from "@ark-ui/react/field";import { createSlotRecipeContext } from "#lib/ark-ui/create-slot-recipe-context.tsx";import { defineSlotRecipe } from "#lib/recipe-props.ts";import { fontSizes } from '@stylexblocks/ui/tokens/font-sizes.stylex.ts'import { fontWeights } from '@stylexblocks/ui/tokens/font-weights.stylex.ts'import { lineHeights } from '@stylexblocks/ui/tokens/line-heights.stylex.ts'import { semanticColors } from '@stylexblocks/ui/semantic-tokens/colors.stylex.ts'import { spacing } from '@stylexblocks/ui/tokens/spacing.stylex.ts'
const fieldRequiredIndicator = stylex.create({ base: { color: semanticColors.fgError, lineHeight: 1, },})
const fieldRoot = stylex.create({ base: { display: 'flex', width: '100%', position: 'relative', gap: spacing._1_5, },})
const fieldRootOrientations = stylex.create({ vertical: { flexDirection: 'column', alignItems: 'flex-start', }, horizontal: { display: 'grid', gridTemplateColumns: 'var(--field-label-width, 8rem) 1fr', alignItems: 'center', },})
const fieldLabel = stylex.create({ base: { display: 'flex', alignItems: 'center', textAlign: 'start', fontSize: fontSizes.sm, lineHeight: lineHeights.sm, fontWeight: fontWeights.medium, gap: spacing._1, userSelect: 'none', opacity: { default: null, ':is(:disabled, [disabled], [data-disabled])': 0.5, }, },})
const fieldErrorText = stylex.create({ base: { display: 'inline-flex', alignItems: 'center', fontWeight: fontWeights.medium, gap: spacing._1, color: semanticColors.fgError, fontSize: fontSizes.xs, lineHeight: lineHeights.xs, },})
const fieldErrorTextOrientations = stylex.create({ horizontal: { gridColumn: 2, },})
const fieldHelperText = stylex.create({ base: { color: semanticColors.fgMuted, fontSize: fontSizes.xs, lineHeight: lineHeights.xs, },})
const fieldHelperTextOrientations = stylex.create({ horizontal: { gridColumn: 2, },})
export type FieldOrientation = keyof typeof fieldRootOrientations
const fieldRecipe = defineSlotRecipe({ slots: { requiredIndicator: { styles: fieldRequiredIndicator }, root: { styles: fieldRoot, orientations: fieldRootOrientations }, label: { styles: fieldLabel }, errorText: { styles: fieldErrorText, orientations: fieldErrorTextOrientations }, helperText: { styles: fieldHelperText, orientations: fieldHelperTextOrientations }, }, defaultVariants: { orientation: "vertical" },});
function RequiredIndicatorNode({ children, ...props}: React.ComponentProps<typeof ArkField.RequiredIndicator>) { return ( <ArkField.RequiredIndicator {...props}>{children ?? "*"}</ArkField.RequiredIndicator> );}
const { withProvider, withContext } = createSlotRecipeContext(fieldRecipe);
/** * Field — Ark UI's field machine (label/control wiring, helper and error * text) wearing the field slot recipe. `<Field.Root orientation>` resolves * the recipe once and every part inherits it through context. */export const Field = { Root: withProvider(ArkField.Root, "root", "FieldRoot"), Label: withContext(ArkField.Label, "label", "FieldLabel"), RequiredIndicator: withContext( RequiredIndicatorNode, "requiredIndicator", "FieldRequiredIndicator", ), Input: ArkField.Input, HelperText: withContext(ArkField.HelperText, "helperText", "FieldHelperText"), ErrorText: withContext(ArkField.ErrorText, "errorText", "FieldErrorText"),};
export type FieldRootProps = React.ComponentProps<typeof Field.Root>;export type FieldLabelProps = React.ComponentProps<typeof Field.Label>;export type FieldRequiredIndicatorProps = React.ComponentProps<typeof Field.RequiredIndicator>;export type FieldInputProps = ArkField.InputProps;export type FieldHelperTextProps = React.ComponentProps<typeof Field.HelperText>;export type FieldErrorTextProps = React.ComponentProps<typeof Field.ErrorText>;