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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions