npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

a11y-conditional-fields

v1.0.1

Published

Framework-agnostic progressive enhancement for accessible conditional form sections.

Readme

A11y Conditional Fields

Framework-agnostic progressive enhancement for accessible conditional form sections.

Installation

This package is configured for npm publishing. Before sharing the npm install commands publicly, confirm the package has been published under the configured name.

npm install a11y-conditional-fields
pnpm add a11y-conditional-fields
yarn add a11y-conditional-fields

Usage

import { createConditionalFields } from "a11y-conditional-fields";

const form = document.querySelector("[data-a11y-conditional-fields]");

if (form instanceof HTMLFormElement) {
  const conditionalFields = createConditionalFields(form, {
    announceChanges: true,
    disableWhenHidden: true
  });

  conditionalFields.refresh();
}

The package is ESM-only and does not auto-initialize on import.

Distribution Files

The default package entry points to the readable ESM build at dist/index.js. npm run build also emits a minified runtime bundle at dist/index.min.js for static-site, CDN, and other pre-minified ESM use cases.

Most app bundlers should use the default import:

import { createConditionalFields } from "a11y-conditional-fields";

Use the minified subpath when you specifically need the pre-minified runtime:

import { createConditionalFields } from "a11y-conditional-fields/min";

The ./min subpath exposes the same public API and reuses the same dist/index.d.ts declarations. Docs metadata remains available from a11y-conditional-fields/docs.

HTML Structure

Use a form root, unique ids on conditional sections, and trigger attributes that point to those ids. Multiple target ids can be separated with spaces.

<form data-a11y-conditional-fields>
  <label>
    <input type="checkbox" data-condition-toggle="shipping-address delivery-notes">
    Use a different shipping address
  </label>

  <section id="shipping-address" data-condition-target hidden aria-labelledby="shipping-title">
    <h2 id="shipping-title">Shipping address</h2>
    <label for="street">Street</label>
    <input id="street" name="street" data-required-when-visible>
  </section>

  <section id="delivery-notes" data-condition-target hidden aria-labelledby="delivery-title">
    <h2 id="delivery-title">Delivery notes</h2>
    <label for="notes">Notes for the courier</label>
    <textarea id="notes" name="notes"></textarea>
  </section>

  <p data-condition-status></p>
</form>

Supported triggers:

  • input[type="checkbox"][data-condition-toggle]
  • button[data-condition-toggle]
  • input[type="radio"][data-condition-show]
  • select[data-condition-select] with option-level data-condition-show

Useful data attributes:

  • data-condition-target marks a hideable section. Give every target a unique id.
  • data-required-when-visible makes a field required only while its section is visible.
  • data-disable-when-hidden opts a field into disabled-when-hidden behavior.
  • data-condition-preserve prevents automatic disable or clear behavior for that field. Preserved named controls can remain submit-eligible while hidden.
  • data-clear-when-hidden clears a field when its section hides.
  • data-focus-first on a target or data-focus-when-shown on a field opts into focus movement.
  • data-condition-status provides a live region for show/hide announcements.
  • data-error marks validation text that should be hidden and disconnected when a target hides.

API

import {
  A11yConditionalFields,
  createConditionalFields,
  initConditionalFieldsAll
} from "a11y-conditional-fields";
  • createConditionalFields(form, options) initializes one form and returns a ConditionalFieldsInstance.
  • initConditionalFieldsAll(options, root) initializes every form[data-a11y-conditional-fields] in a document or subtree.
  • new A11yConditionalFields(form, options) is available for class-based integration.
  • refresh() rescans dynamic targets and triggers.
  • show(targetId), hide(targetId), toggle(targetId, visible), and isVisible(targetId) manage known targets by id.
  • destroy() removes listeners, restores managed attributes and field state, and allows the form to be initialized again.

Options:

| Option | Default | Description | |---|---:|---| | clearWhenHidden | false | Clears managed fields when their section hides, unless the field has data-condition-preserve. | | disableWhenHidden | true | Disables managed controls while hidden so they are skipped by keyboard and form submission. | | announceChanges | true | Uses a polite status region for show/hide messages. | | focusFirstOnShow | false | Moves focus to the first focusable field when a target opens. | | validateOnHide | false | Calls checkValidity() after fields are hidden. | | collapseOnEscape | false | Lets Escape hide a visible controlled section that contains focus. |

The same boolean options can be set as data attributes on the form, such as data-clear-when-hidden="true" or data-collapse-on-escape="true". JavaScript options take precedence.

Submission Behavior

By default, hidden managed fields are disabled before submission. Native form submission and new FormData(form) skip disabled controls, so hidden section values are not sent unless you opt out of that behavior.

Hiding a section does not clear values by default. The values stay in the DOM and are available again if the section is shown later. Use clearWhenHidden or data-clear-when-hidden when stale hidden values should be erased.

If you set disableWhenHidden: false or add data-condition-preserve to a field, that named control can stay enabled while hidden. Treat that as an application data decision: filter hidden values before submit, or intentionally accept them in your server-side handling.

Keyboard Behavior

| Key or action | Behavior | |---|---| | Tab / Shift+Tab | Follows the native form order. Hidden conditional fields are not focusable. | | Enter / Space on a checkbox or button trigger | Uses native control behavior to update the target section. | | Arrow keys in radio groups or selects | Uses native browser behavior for the form control. | | Escape inside an open target | When collapseOnEscape is enabled, hides that target and restores focus to its controlling trigger. |

Accessibility Notes

The plugin starts from semantic form markup. It keeps hidden sections out of keyboard and assistive-technology flows with hidden, inert, aria-hidden, and disabled form controls. It adds aria-controls and aria-expanded to checkbox, radio, and button triggers, and it uses a polite role="status" live region when announcements are enabled.

Use data-required-when-visible for fields that should only be required while their section is visible. Existing validation errors marked with data-error are hidden and disconnected from aria-describedby or aria-errormessage when their section hides. Keep labels or legends near the controls that reveal conditional fields.

Focus stays on the current control by default. Add data-focus-first to a target or data-focus-when-shown to a specific field only when moving focus reduces effort. When collapseOnEscape is enabled, pressing Escape inside a visible conditional target hides that target and restores focus to its controlling trigger.

Still test the final form with the browsers and assistive technologies your audience uses. The plugin manages section state; it does not prove that the surrounding form copy, validation flow, or data model is accessible.

Lifecycle Events

Lifecycle events bubble from the form and include the plugin instance in event.detail.instance.

  • a11y-conditional-fields:init
  • a11y-conditional-fields:refresh
  • a11y-conditional-fields:show
  • a11y-conditional-fields:hide
  • a11y-conditional-fields:change
  • a11y-conditional-fields:destroy

Show, hide, and change events also include targetId, target, trigger, and visible.

Limitations

  • The plugin does not create form markup for you.
  • Targets without an id are ignored because triggers need stable references.
  • It does not provide an error summary or custom validation UI.
  • It does not add custom arrow-key behavior to native form controls.
  • Live-region output is intentionally short and still needs manual screen reader verification.
  • There is no CSS export; bring your own form and focus styles.

Examples

  • examples/basic shows a semantic form using checkbox, radio, select, default focus retention, Escape focus restoration, and live-region patterns.
  • examples/options-lab compares the main options, including focusFirstOnShow, collapseOnEscape, clearWhenHidden, validateOnHide, announceChanges, and disableWhenHidden.
  • examples/form-validator-integration combines conditional fields with a11y-form-validator so hidden sections do not block validation while visible follow-up fields still receive summaries and inline errors.

Build the package before opening an example because examples import from ../../dist/index.js.

npm run build
python3 -m http.server 4173

Then open one of these URLs:

  • http://127.0.0.1:4173/examples/basic/
  • http://127.0.0.1:4173/examples/options-lab/
  • http://127.0.0.1:4173/examples/form-validator-integration/

GitHub Pages Demo

The root index.html is a static demo and compact documentation page. Build the package and assemble the Pages artifact with:

npm run build:pages

The generated _site/ folder contains index.html, the example pages, dist/, the validator demo assets, and .nojekyll. Configure GitHub Pages to use GitHub Actions. After deployment, the project page is expected at:

https://vmitsaras.github.io/a11y-conditional-fields/

Docs Metadata

import { docs } from "a11y-conditional-fields/docs";

License

MIT