10x-media plugins
Form Builder

Styling

Style forms with CSS on the class hooks, the shadcn registry, or your own renderers.

The renderer is headless by design. Pick the lightest path that fits your project.

Path 1: CSS on the class hooks

The built-in renderers emit stable classes. Write CSS against them and change nothing else:

ClassElement
fb-fieldWrapper div around the entire field
fb-field__labellabel
fb-field__requiredRequired asterisk span (aria-hidden)
fb-field__messagesDescription + errors region
fb-field__descriptionDescription line
fb-field__errorsError group (role="alert", aria-atomic)
fb-field__errorIndividual error messages
fb-input / fb-textarea / fb-select / fb-checkboxThe controls

The field wrapper carries data-invalid when the field has errors:

.fb-field[data-invalid] .fb-input {
  border-color: red;
}

For the optional grid, import the stylesheet and use FormLayout + widthProps (Rendering); the grid uses fb-form--grid on the container and data-width on each slot.

Path 2: the shadcn registry

For projects on shadcn, a registry block installs styled field renderers and a preconfigured <FormBuilderForm> into your codebase. You own the copied files.

The registry JSON builds to registry/r/form.json in the package source; hosting it is a follow-up. Until then, point the CLI at the raw file:

npx shadcn@latest add <registry-url>/r/form.json

Installed: the @10x-media/form-builder dependency, shadcn input/textarea/label primitives, components/form-builder/form-builder-form.tsx, a shadcnRenderers map, and a styled renderer for every built-in field type under components/form-builder/fields/.

import { FormBuilderForm } from '@/components/form-builder/form-builder-form'

<FormBuilderForm form={form} onSuccess={(id) => console.log('submitted', id)} />

<FormBuilderForm> is <Form> preconfigured with the styled renderers; any renderers prop you pass merges on top. The shipped styling is a baseline to edit, not an API.

Path 3: your own renderers or markup

Replace renderers per type with defineFieldRenderer + resolveRenderers, or take full markup control with children + useField. Both are covered in Rendering, including the a11y contract custom renderers must uphold.

Choosing

  • Existing design system with CSS conventions: Path 1.
  • shadcn project that wants a working styled form now: Path 2.
  • Component library with its own inputs, or exact markup requirements: Path 3.

The paths compose: shadcn for most fields plus one custom renderer for a bespoke type is a normal setup.

On this page