Skip to content

Type to search the docs, API, and blog.

↑↓ navigate↵ openesc close
Zazz 0.13 alpha
API navigation

API

Group

An ancestor whose state its descendants follow.

Installation

pnpm dlx zazz-ui add group
npx zazz-ui add group
yarn dlx zazz-ui add group
bunx zazz-ui add group

Run zazz-ui init first if the project has no zazz/ folder yet.

<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Paint the right theme (background, form controls, scrollbars) before CSS loads -->
<meta name="color-scheme" content="light dark">
<!-- Zazz styles: base layers, then group in cascade order -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_layers.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_variables.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_shadows.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_breakpoints.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_reset.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_typography.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_view-transitions.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/primitives/group/group.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_properties.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_properties-sm.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_properties-md.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_properties-lg.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_properties-xl.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_properties-2xl.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_properties-disabled.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_properties-active.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_properties-focus-visible.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_properties-focus-within.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_properties-hover.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_properties-checked.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_properties-current.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_properties-open.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_properties-stuck.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_properties-starting.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-tier-sm.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-tier-md.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-tier-lg.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-tier-xl.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-tier-2xl.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-tier-disabled.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-tier-active.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-tier-focus-visible.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-tier-focus-within.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-tier-hover.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-tier-checked.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-tier-current.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-tier-open.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-tier-stuck.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-tier-starting.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-flow.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-grid.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-spacing.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-margin.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-sizing.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-typography.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-color.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-effects.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-box.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-pseudo.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_defaults.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/_utilities-sr.css">
<!-- Import map: bare specifiers in Zazz scripts resolve to pinned, SRI-checked files -->
<script type="importmap">
{
  "imports": {
    "signal-polyfill": "https://cdn.jsdelivr.net/npm/signal-polyfill@0.2.2/dist/index.js",
    "embla-carousel": "https://cdn.jsdelivr.net/npm/embla-carousel@9.0.0-rc04/esm/embla-carousel.esm.js",
    "embla-carousel-autoplay": "https://cdn.jsdelivr.net/npm/embla-carousel-autoplay@9.0.0-rc04/esm/embla-carousel-autoplay.esm.js",
    "embla-carousel-auto-scroll": "https://cdn.jsdelivr.net/npm/embla-carousel-auto-scroll@9.0.0-rc04/esm/embla-carousel-auto-scroll.esm.js",
    "embla-carousel-class-names": "https://cdn.jsdelivr.net/npm/embla-carousel-class-names@9.0.0-rc04/esm/embla-carousel-class-names.esm.js"
  },
  "integrity": {
    "https://cdn.jsdelivr.net/npm/signal-polyfill@0.2.2/dist/index.js": "sha384-0OqM7OXGT6Oz1z98u/geiFn/FUyz4iWexkXHCvbIGXRRDXl6bp6IKc0j78AQ6DEK",
    "https://cdn.jsdelivr.net/npm/embla-carousel@9.0.0-rc04/esm/embla-carousel.esm.js": "sha384-Qcz5VJ/iRhG3zPRMT8li6rYNSsXcCeSQ6URxPlQh7joEd/nNxRRkCZxlJoTZr3Ch",
    "https://cdn.jsdelivr.net/npm/embla-carousel-autoplay@9.0.0-rc04/esm/embla-carousel-autoplay.esm.js": "sha384-dsPLKoLTpj/hIVD1I1zYA1kDCI32uRH4seU3ly+s7Lm9MdWVsj1OmE8HELhZ/Fm4",
    "https://cdn.jsdelivr.net/npm/embla-carousel-auto-scroll@9.0.0-rc04/esm/embla-carousel-auto-scroll.esm.js": "sha384-bOWyJNYHSsncAhdIgavN6TjY6Bb/NRLV9fAon5xy9HquiFZbNYTjq2JZ5bq5nyb5",
    "https://cdn.jsdelivr.net/npm/embla-carousel-class-names@9.0.0-rc04/esm/embla-carousel-class-names.esm.js": "sha384-y8wWJW7HPdqr5guB+ZdF/o9FIRGg2KtH9TdoAttP7jjEU9bQlAzY0Fc5FiIMYQN1"
  }
}
</script>
<!-- Polyfill: Interest Invokers (interestfor) — native in Chromium only -->
<script type="module" src="https://cdn.jsdelivr.net/npm/invokers@2.2.2/dist/esm/production/interest.js" integrity="sha384-hR2BVNtsS7fIIMwOm+f7MY0JZfuByGhQQfevCBB6evFATKzBsTw0JzH/RxD94z2T" crossorigin="anonymous"></script>
<!-- Zazz behavior: side-effect modules by tag; the rest via module imports -->
<script type="module" src="https://cdn.jsdelivr.net/npm/@zazz-ui/core@0.13.0/src/base/dialog-lifecycle.js"></script>
<!-- Theme: apply the persisted (or preferred) scheme before first paint -->
<script>
  (() => {
    try {
      // A stored choice pins the scheme with data-theme; with no choice the
      // page follows the system scheme.
      const storedTheme = localStorage.getItem("theme");
      if (storedTheme === "dark" || storedTheme === "light") {
        document.documentElement.dataset.theme = storedTheme;
      }
    } catch {
      /* no storage access: follow the system scheme */
    }
  })();
</script>

A <head> that loads the base layers and group from jsDelivr, pinned to 0.13.0. To load the whole kit in two requests, see the CDN install.

Source

Examples

Hover anywhere on this card

The text follows the group's state, not its own.

<ui-group
  style="
    --display: block;
    --p: 4;
    --border: 1;
    --radius: 2;
  "
>
  <p
    style="
      --font-weight: strong;
      --text: var(--color-foreground);
      --group-text--hover: var(--color-primary);
    "
  >
    Hover anywhere on this card
  </p>
  <p
    style="
      --opacity: 0.7;
      --group-opacity--hover: 1;
    "
  >
    The text follows the group's state, not its own.
  </p>
</ui-group>
/**
 * group.css: Group (ui-group | [data-ui~="group"]), the ancestor whose state
 * its descendants' `--group-*` utilities follow (`--group-bg--hover`)
 *
 * @layer      components
 * @requires   _layers.css
 *
 * The state selectors live in the generated tier setters. This file only gives
 * the tag a display: the attribute form sits on a link, a button, a list item,
 * and keeps what its host has. A custom element never matches `:disabled`, so
 * `<ui-group>` takes `aria-disabled="true"` (with a role that allows it).
 */

@layer ui.components {
  :where(ui-group) {
    display: block;
  }
}

Tag or attribute

<ui-group> is a block. data-ui="group" keeps its host's display, so use it on a link, a button, or a list item, and stack it on a primitive (data-ui="card group"). Descendants read the group's state with the group modifier.

A custom element never matches :disabled, so <ui-group> takes aria-disabled="true" instead, with a role that allows it.

Attributes

group attributes
AttributeKindValuesNotes
data-ui="group"Identityfree valueIdentity token in data-ui.
<ui-group>Tag formfree valueTag form; styled and, when scripted, registered under this name.