Skip to main content
USWDS + Tailwind

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.

src/main.js
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, Combobox data-disabled, and Modal data-force-action treat the exact string "false" as false.
  • Native disabled and multiple attributes 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.