Skip to content

formspec-adapters: Tailwind CSS adapter reference implementation #8

@mikewolfd

Description

@mikewolfd

Motivation

The adapter architecture (ADR 0046) was validated with the USWDS adapter, but USWDS represents the prescriptive end of the design-system spectrum. Formspec needs to prove the behavior/adapter split works equally well for utility-first CSS frameworks. A Tailwind adapter validates that axis while also serving as the most accessible reference implementation for custom adapter authors — simpler DOM patterns, transparent class strategy, no design-system-specific knowledge required.

See ADR 0049 (thoughts/adr/0049-tailwind-css-adapter.md) for the full decision record.

Scope

Adapter (packages/formspec-adapters/src/tailwind/)

Implement all 15 component types using Tailwind utility classes on semantic HTML:

Category Components
Text inputs TextInput, NumberInput, MoneyInput
Choice inputs RadioGroup, CheckboxGroup, Select
Toggle inputs Checkbox, Toggle
Specialized DatePicker, Slider, Rating, FileUpload, Signature
Interactive Wizard, Tabs

Structure mirrors the USWDS adapter 1:1:

  • index.ts — RenderAdapter barrel export
  • shared.tscreateTailwindFieldDOM(), error helper
  • One file per component type
  • integration-css.ts — Minimal/empty (validates ADR 0047)

CSS class cascade conflict resolution

Two complementary mechanisms:

  1. cssClassReplace (spec-level, framework-agnostic) — new PresentationBlock property that replaces lower-cascade classes by utility prefix during mergeBlocks()
  2. classStrategy: "tailwind-merge" (runtime, opt-in) — ThemeDocument-level option that runs resolved class lists through tailwind-merge as post-processing. Injected via setTailwindMerge() to avoid hard dependency.

Example app (examples/tailwind-demo/)

Vite app with @tailwindcss/vite plugin, definition, and theme demonstrating the adapter end-to-end.

Package export

formspec-adapters exports both uswdsAdapter and tailwindAdapter from its barrel.

Acceptance Criteria

  • All 15 component types implemented with correct FieldRefs contract compliance
  • Adapter structure mirrors USWDS 1:1 for easy comparison
  • Integration CSS is near-zero (validates ADR 0047)
  • cssClassReplace works in theme cascade merging
  • classStrategy: "tailwind-merge" resolves utility conflicts when opt-in is configured
  • examples/tailwind-demo/ renders a functional form with Tailwind styling
  • Host app compiles Tailwind via Vite plugin pointing at adapter source
  • Tests cover adapter output and class conflict resolution

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions