CSS Toggles (in JS)

What are CSS Toggles?

The goal of this (work in progress) feature is to make it possible for CSS to manage presentational state for patterns such as tabs/accordians, carousels, color modes, etc. There are still many questions to be answered around the scope, syntax, and (most importantly) accessibility of a feature like this in CSS.

This polyfill is designed to help us explore those questions. It implements the entire draft spec as currently written, in addition to some of the extensions proposed in our explainer. We're excited for you to play with this, provide additional use-cases, and provide us with feedback:

Global color toggle

This syntax for named states is one of several proposed in the explainer.

html {
  toggle-root: mode [auto light dark];
}

html:toggle(mode light) { ... }
html:toggle(mode dark) { ... }

.mode-btn {
  toggle-trigger: mode;
}

Binary self-toggle switches

.todo li {
  toggle: todo self;
  list-style-type: '❌ ';
}

.todo li:toggle(todo) {
  list-style-type: '✅ ';
}

Accordion/disclosure components

The goal of toggle-visibility is for browsers to handle accessibility and discoverability by default. We'll keep working to improve the polyfill a11y as well, but may not be able to achieve the same results.

Establish a toggle
.accordion>dt {
  toggle: glossary;
}
Toggle item visibility
.accordion>dd {
  toggle-visibility: toggle glossary;
}
Style the summary
.accordion>dt::marker {
  content: '👉🏽 ';
}

.accordion>dt:toggle(glossary) {
  background-color: var(--brand);
  color: var(--bg);
}

.accordion>dt:toggle(glossary)::marker {
  content: '👇🏽 ';
}

Tree view

.nested {
  toggle: tree;
}

.nested+ul {
  toggle-visibility: toggle tree;
}

Tabs or exclusive accordions

issue 9: Not possible to change initial state for one toggle in a group.

Establishing Tabs
panel-tab {
  toggle: tab 1 at 0 group sticky;
  grid-row: tab;
}
Styling Content
panel-tab:toggle(tab) {
  background-color: var(--callout);
}

panel-card {
  toggle-visibility: toggle tab;
  grid-area: card;
}

Named states

This syntax for named states is one of several proposed in the explainer.

.colors {
  toggle-root: colors [grape green blue red] at blue;
}

.colors button {
  toggle-trigger: colors;
}

/* for each color */
.colors button.grape {
  toggle-trigger: colors grape;
}

.show-colors:toggle(colors grape) {
  background-color: var(--grape-9);
}

State machine transitions

This functionality & syntax is proposed in the explainer as syntax sugar on top of the existing functionality. However, it's not yet clear that there are entirely presentational (CSS-only) use-cases. If you have ideas, we'd love to hear from you. The following example would involve JS in production:

@machine request {
  idle {
    try: loading;
  }

  loading {
    resolve: success;
    reject: failure;
    reset: idle;
  }

  failure {
    try: loading;
    reset: idle;
  }

  success {
    reset: idle;
  }
}

/* establish a toggle based on the machine */
.request {
  toggle-root: machine(request);
}

/* the individual trigger buttons call 'transitions' */
.request button[data-do="try"] {
  toggle-trigger: request do(try);
}