What is headless?
A headless component defines how an interactive component works without prescribing how it looks.
USWDS + Tailwind builds on Zag, which models component interactions with state machines. A shared interaction logic can be connected to different frameworks and styled for different design systems.
Components as state
Our headless components are unstyled, but they have a defined structure and behavior. This ensures that component behavior is consistent, regardless of the design system they’re applied to.
{
"props": {
"multiple": true,
"defaultValue": [
"one"
]
},
"context": {
"value": [
"one"
]
}
}Build your own
You can use predefined state machines to build your own components. The following example shows how to implement an accordion component in React using the @uswds-tailwind/accordion-compat package.
Zag provides adapters for other frameworks, including Vue, Solid, and Svelte. USWDS + Tailwind uses the Vanilla JavaScript and React adapters.
import * as accordion from '@uswds-tailwind/accordion-compat'import { normalizeProps, useMachine } from '@zag-js/react'import { useId } from 'react'
const items = [ { value: 'one', label: 'First item', content: 'First panel.' }, { value: 'two', label: 'Second item', content: 'Second panel.' },]
export function MyAccordion() { const id = useId() const service = useMachine(accordion.machine, { id, multiple: true, defaultValue: ['one'], }) const api = accordion.connect(service, normalizeProps)
return ( <div className="accordion" {...api.getRootProps()}> {items.map(item => ( <div className="accordion__item" {...api.getItemProps(item)} key={item.value}> <button className="accordion__button" {...api.getItemTriggerProps(item)}> {item.label} </button> <div className="accordion__panel" {...api.getItemContentProps(item)}> {item.content} </div> </div> ))} </div> )}