API
Group
An ancestor whose state its descendants follow.
Installation
pnpm dlx zazz-ui add groupnpx zazz-ui add groupyarn dlx zazz-ui add groupbunx zazz-ui add groupRun 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.
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
| Attribute | Kind | Values | Notes |
|---|---|---|---|
data-ui="group" | Identity | free value | Identity token in data-ui. |
<ui-group> | Tag form | free value | Tag form; styled and, when scripted, registered under this name. |