JavaScript
Initialize components, configure their authored markup, and manage instance lifecycles with @uswds-tailwind/compat.
The package binds Zag state machines to HTML. Import its initializers from @uswds-tailwind/compat; no framework plugin is required. For package installation and Tailwind setup, start with the getting-started guide. React components own their own behavior; do not run these initializers on React-rendered markup.
Choose an initialization strategy
| Approach | Use when |
|---|---|
| Selective initialization | You know which components the page uses. |
| Initialize all components | A static page needs all available behaviors. |
| Owned instances | Your application adds and removes component markup. |
Selective initialization
Import only the initializers you need. Each scans the document synchronously when called; it does not wait for the DOM, observe future additions, or return a promise.
import { accordionInit } from '@uswds-tailwind/compat/accordion'import { collapseInit } from '@uswds-tailwind/compat/collapse'
function initialize() { accordionInit() collapseInit()}
if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initialize, { once: true })} else { initialize()}Root imports such as import { accordionInit } from '@uswds-tailwind/compat' expose the same functions.
Initialize all components
Choose one initialization strategy per element. The auto entry point runs initAll() immediately when the document is ready, or on DOMContentLoaded if it is still loading:
import '@uswds-tailwind/compat/auto'To control when the scan happens, import the function instead and call it after inserting the markup:
import { initAll } from '@uswds-tailwind/compat'
// After all component markup is in the document:initAll()These are alternative entry points, not imports to combine. initAll() returns void. Later scans reuse existing instances and initialize newly inserted roots. Destroy instances before removing their markup.
Authored markup and generated state
Copy the complete component example, including required parts, labels, and Tailwind classes. Each reference separates authored configuration from generated state.
| Markup | Purpose |
|---|---|
data-scope="accordion" data-part="root" |
v2 wrappers use scoped roots and short descendant parts. Follow each component’s anatomy. |
| Configuration attributes and constructor options | Inputs read during construction; later attribute changes are not automatically observed. |
Generated IDs, aria-*, hidden, and state attributes |
Output used for accessibility and styling. Treat only documented configuration as writable input. |
Boolean attributes
- v2 data booleans such as Accordion
data-multiple, Comboboxdata-disabled, and Modaldata-force-actiontreat the exact string"false"as false. - Native
disabledandmultipleattributes follow HTML presence rules. - Constructor precedence varies by component; check its configuration table.
Instance lifecycle
Accordion, Character Count, Collapse, Combobox, Date Picker, Date Range Picker, Dropdown, File Input, Input Mask, Modal, Table, and Tooltip support these shared methods:
| Method | Result and behavior |
|---|---|
new Component(elementOrSelector, options) |
Constructs an instance without starting it. Throws if the root is missing or already bound to a component. |
instance.init() |
Starts rendering and the machine; returns the instance. Call once. |
Component.getInstance(elementOrSelector) |
Returns the instance for that element and type, or null. Use an element or CSS selector, not a bare ID string. |
Component.getOrCreateInstance(elementOrSelector, options) |
Returns the existing instance or constructs and initializes one. Options do not reconfigure an existing instance. |
Component.createAll(container) |
Finds matching descendant roots and returns an array of initialized instances. Defaults to document; the container itself is not included in the scan. |
instance.destroy() |
Stops the machine and removes the element lookup. Returns void; it does not restore authored HTML or remove the root. |
All twelve convenience initializers return instance arrays and reuse existing instances. Date Picker and Date Range Picker use the same element-based lookup and cleanup methods.
For dynamic content, retain an explicit instance and destroy it before removing the owned DOM:
import { Collapse } from '@uswds-tailwind/compat/collapse'
// <section id="details" data-scope="collapse" data-part="root">// <button type="button" data-part="trigger">Details</button>// <div data-part="content">More information</div>// </section>const root = document.querySelector('#details')const details = Collapse.getOrCreateInstance(root, { id: 'details', onOpenChange({ open }) { console.log('Requested open state:', open) },})
await details.open()
// When the application removes this section:details.destroy()root.remove()Cleanup
- Retain the root element reference: initialization can replace its ID.
- Destroy the instance before removing its DOM. Modal moves its root to the document body, so remove that root too.
- Start a fresh mount with fresh authored markup;
destroy()does not restore the original HTML.
Changes and callbacks
Pass callbacks through explicit constructor or factory options. These are JavaScript callbacks, not automatically emitted custom DOM events. File Input exposes accepted files and validation state through instance.api; it does not provide change callbacks.
| Component | Callback | Payload |
|---|---|---|
| Accordion | onValueChange |
{ value: string[] } |
| Collapse, Tooltip | onOpenChange |
{ open: boolean } |
| Character Count | onValueChange |
{ value: string } |
| Combobox | onValueChange |
{ value: string, label: string } |
| Table | onSortChange |
{ sortDescriptor: { column: number, direction: "ascending" | "descending" } | null } |
| Dropdown | onItemSelect |
{ value } |
| Input Mask | onValueChange |
{ value: string } (formatted) |
Accordion, Character Count, and Input Mask support controlled value; Collapse and Tooltip support controlled open. Table supports controlled sortDescriptor. Dropdown and Modal manage open state internally and do not accept open or onOpenChange. When you supply a supported controlled prop, your application controls that state. Change callbacks request a new value; your application must supply the updated state. Use the component’s documented initial-state options for uncontrolled state.
Wrapper open()/close() methods on Accordion, Collapse, Dropdown, and Modal return promises that settle the queued update; they do not wait for CSS transitions or update state controlled by your application. Direct connect API requests such as Input Mask’s instance.api.setValue() return no promise.
JavaScript components
All subpaths below are relative to @uswds-tailwind/compat/. Each initializer binds the corresponding authored markup; presentation-only components need no initializer.
| Component reference | Import subpath | Initializer |
|---|---|---|
| Accordion | accordion |
accordionInit() |
| Character Count | character-count |
characterCountInit() |
| Collapse | collapse |
collapseInit() |
| Combobox | combobox |
comboboxInit() |
| Date Picker | date-picker |
datePickerInit() |
| Date Range Picker | date-range-picker |
dateRangePickerInit() |
| Dropdown | dropdown |
dropdownInit() |
| File Input | file-input |
fileInputInit() |
| Input Mask | input-mask |
inputMaskInit() |
| Modal | modal |
modalInit() |
| Table | table |
tableInit() |
| Tooltip | tooltip |
tooltipInit() |
Banner uses Collapse; Header and Language Selector use Dropdown. Time Picker uses Combobox. Ordinary styled tables need no JavaScript. Header and expandable Footer examples also use Accordion.