---
title: JavaScript (Vanilla) - USWDS + Tailwind
description: Initialize components, configure their authored markup, and manage
  instance lifecycles with @uswds-tailwind/compat.
---

# 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](https://uswds-tailwind.com/docs/vanilla/getting-started). React components own their own behavior; do not run these initializers on React-rendered markup.

## Choose an initialization strategy

| Approach | Use when |
| - | - |
| [Selective initialization](https://uswds-tailwind.com/docs/vanilla/javascript#selective-initialization) | You know which components the page uses. |
| [Initialize all components](https://uswds-tailwind.com/docs/vanilla/javascript#initialize-all-components) | A static page needs all available behaviors. |
| [Owned instances](https://uswds-tailwind.com/docs/vanilla/javascript#instance-lifecycle) | 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.

```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:

```js
import '@uswds-tailwind/compat/auto'
```

To control when the scan happens, import the function instead and call it after inserting the markup:

```js
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:

```js
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](https://uswds-tailwind.com/docs/vanilla/components/accordion#component-api) | `accordion` | `accordionInit()` |
| [Character Count](https://uswds-tailwind.com/docs/vanilla/components/character-count#component-api) | `character-count` | `characterCountInit()` |
| [Collapse](https://uswds-tailwind.com/docs/vanilla/components/banner#component-api) | `collapse` | `collapseInit()` |
| [Combobox](https://uswds-tailwind.com/docs/vanilla/components/combo-box#component-api) | `combobox` | `comboboxInit()` |
| [Date Picker](https://uswds-tailwind.com/docs/vanilla/components/date-picker#component-api) | `date-picker` | `datePickerInit()` |
| [Date Range Picker](https://uswds-tailwind.com/docs/vanilla/components/date-range-picker#component-api) | `date-range-picker` | `dateRangePickerInit()` |
| [Dropdown](https://uswds-tailwind.com/docs/vanilla/components/language-selector#component-api) | `dropdown` | `dropdownInit()` |
| [File Input](https://uswds-tailwind.com/docs/vanilla/components/file-input#component-api) | `file-input` | `fileInputInit()` |
| [Input Mask](https://uswds-tailwind.com/docs/vanilla/components/input-mask#component-api) | `input-mask` | `inputMaskInit()` |
| [Modal](https://uswds-tailwind.com/docs/vanilla/components/modal#component-api) | `modal` | `modalInit()` |
| [Table](https://uswds-tailwind.com/docs/vanilla/components/table#component-api) | `table` | `tableInit()` |
| [Tooltip](https://uswds-tailwind.com/docs/vanilla/components/tooltip#component-api) | `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.
