{
  "generatedFrom": "setting-group.contract.json",
  "component": "Setting group",
  "slug": "setting-group",
  "group": "Settings",
  "tier": "leaf-lit",
  "summary": "The settings GROUP container — an optional semibold header (with a \"?\" help and an action slot) over a column of rows — that bakes in the panel spacing scale so gaps come out right automatically.",
  "install": {
    "package": "@ahaslides-product/design",
    "registry": "https://npm.pkg.github.com",
    "scope": "@ahaslides-product",
    "auth": "Published to GitHub Packages — needs a GitHub token with read:packages. Configure the @ahaslides-product scope in .npmrc before installing.",
    "npmrc": "@ahaslides-product:registry=https://npm.pkg.github.com\n//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}   # a GitHub token with read:packages",
    "command": "npm i @ahaslides-product/design",
    "tokenLayer": "import '@ahaslides-product/design/tokens.css';",
    "import": "import '@ahaslides-product/design/aha-setting-group';",
    "element": "aha-setting-group",
    "registers": "aha-setting-group"
  },
  "feeds": {
    "doc": "https://ahaslides-product.github.io/ahaslides-design/setting-group/index.html",
    "md": "https://ahaslides-product.github.io/ahaslides-design/setting-group/setting-group.md",
    "agentJson": "https://ahaslides-product.github.io/ahaslides-design/setting-group.agent.json",
    "llms": "https://ahaslides-product.github.io/ahaslides-design/setting-group.llms.txt",
    "index": "https://ahaslides-product.github.io/ahaslides-design/llms.txt"
  },
  "recommendedSnippet": "html",
  "vibeCode": "Emit the HTML snippet by default — <aha-setting-group> is a standard custom element that renders on open — React/Vue are thin adapters over the same element. Paste into an .html file and it renders with no build step.",
  "frameworks": {
    "react": {
      "via": "web-component",
      "ref": "aha-setting-group"
    },
    "vue": {
      "via": "web-component",
      "ref": "aha-setting-group"
    },
    "html": {
      "via": "web-component",
      "ref": "aha-setting-group",
      "runnable": "paste-and-run — no build step, renders on open"
    }
  },
  "props": [
    {
      "name": "label",
      "type": "string",
      "default": "—",
      "desc": "Optional group header (a 1–3 word noun phrase). When set, renders a semibold header and becomes the group's aria-label"
    },
    {
      "name": "help",
      "type": "string",
      "default": "—",
      "desc": "Optional guidance shown as the \"?\" help tooltip (composed DS <aha-tooltip help>) after the header label — never a standing line"
    },
    {
      "name": "tone",
      "type": "'default' | 'danger'",
      "default": "default",
      "desc": "danger → a danger-zone group, dropped 48px below the previous group (overrides the automatic 32). Spacing only — the danger CTA styling lives on the button"
    },
    {
      "name": "action",
      "type": "slot",
      "default": "—",
      "desc": "Forwarded to the header, right-aligned — e.g. a small link or button beside the group title"
    },
    {
      "name": "(default slot)",
      "type": "slot",
      "default": "—",
      "desc": "The setting rows / sub-groups; they stack 16px apart automatically"
    }
  ],
  "tokens": [
    "text-default",
    "text-tertiary",
    "bg-container"
  ],
  "spec": [
    {
      "label": "Rows",
      "value": "column · 16px between sibling settings (the settings scale) · header→rows 12px"
    },
    {
      "label": "Between groups",
      "value": "32px automatically (:host(:not(:first-child))) — no divider, no wiring"
    },
    {
      "label": "Danger zone",
      "value": "tone=danger → 48px above (overrides the 32); the danger CTA styling lives on the button, not here"
    },
    {
      "label": "Header",
      "value": "optional (label) · 14/21 Semibold (600) #1A1A1A · optional \"?\" help (composed <aha-tooltip help>) · action slot pushed right (margin-left:auto)"
    },
    {
      "label": "Structure",
      "value": "no divider lines, no card/box — spacing only, white background"
    }
  ],
  "opinion": {
    "whenToUse": [
      {
        "what": "Setting group",
        "when": "a titled cluster of related settings in a panel — it bakes in the 16/32/48 spacing scale"
      },
      {
        "what": "Sub setting group",
        "when": "dependent child settings that appear under one parent toggle (indent + tight gap)"
      },
      {
        "what": "Settings list",
        "when": "you want the whole surface rendered from a schema (rows + reused DS controls) in one element"
      }
    ],
    "note": "Reach for a group whenever you place more than one setting in a panel — it removes the temptation to eyeball gaps or draw a divider. Title it with a noun phrase; put guidance in the \"?\" help, not a standing line. Never wrap plain settings in a card or separate them with a line — hierarchy is spacing. Reserve tone=\"danger\" for a genuine danger zone (delete / reset), and put the destructive styling on the CTA button inside it."
  },
  "surfaces": [
    "editor",
    "settings",
    "dashboard"
  ],
  "snippets": {
    "html": "<!-- Paste-and-run: save as .html and open in a browser. No build step.\n     <aha-setting-group> is the SAME shared custom element React and Vue consume — here in its\n     native form. It BAKES IN the settings-panel spacing scale: rows 16px apart, groups 32px apart\n     automatically, a danger zone 48px down — no dividers, no cards, white bg. Theming comes only\n     from the --aha-* tokens in tokens.css. -->\n<link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/tokens.css\">\n<script type=\"module\">\n  import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/icons.js';                  // <aha-icon> — the header \"?\" help glyph + row controls\n  import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/aha-setting-group.js';      // registers <aha-setting-group>\n  import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/aha-sub-setting-group.js';  // registers <aha-sub-setting-group> (the nested cluster)\n  import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/aha-settings-list.js';      // <aha-settings-item> rows (reused for the labelled rows)\n  import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/aha-switch.js';             // reused row control\n  import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/aha-input.js';              // reused row control\n  import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/aha-button.js';            // the danger-zone CTA (danger styling lives on the button)\n</script>\n\n<!-- A mini settings panel: TWO groups → the 32px between-group gap is automatic (you set nothing),\n     and the first group has a row with a nested sub-setting-group (8px above + 24px indent). -->\n<div style=\"max-width:380px\">\n\n  <!-- Group 1 — an optional header (semibold) + a \"?\" help; rows sit 16px apart on their own. -->\n  <aha-setting-group label=\"Presentation\" help=\"How the deck shows to the audience.\">\n    <aha-settings-item label=\"Progress bar\">\n      <aha-switch slot=\"control\" checked></aha-switch>\n    </aha-settings-item>\n\n    <!-- A parent toggle + its dependent settings, nested + hidden when the parent is off. -->\n    <aha-settings-item label=\"Question timer\">\n      <aha-switch slot=\"control\" id=\"timerToggle\" checked></aha-switch>\n    </aha-settings-item>\n    <aha-sub-setting-group id=\"timerSub\">\n      <aha-settings-item label=\"Seconds per question\">\n        <aha-input slot=\"control\" value=\"30\"></aha-input>\n      </aha-settings-item>\n      <aha-settings-item label=\"Auto-advance\">\n        <aha-switch slot=\"control\"></aha-switch>\n      </aha-settings-item>\n    </aha-sub-setting-group>\n  </aha-setting-group>\n\n  <!-- Group 2 — no wiring: it just sits 32px below Group 1 automatically. -->\n  <aha-setting-group label=\"Audience\">\n    <aha-settings-item label=\"Anonymous join\">\n      <aha-switch slot=\"control\" checked></aha-switch>\n    </aha-settings-item>\n  </aha-setting-group>\n\n  <!-- A danger zone — tone=\"danger\" drops it 48px below the previous group (the CTA carries the danger look). -->\n  <aha-setting-group tone=\"danger\" label=\"Danger zone\">\n    <aha-settings-item label=\"Reset all scores\">\n      <aha-button slot=\"control\" danger>Reset</aha-button>\n    </aha-settings-item>\n  </aha-setting-group>\n\n</div>\n\n<script>\n  // The parent toggle hides its dependent sub-group when off — visibility is the author's job.\n  const sub = document.getElementById('timerSub');\n  document.getElementById('timerToggle').addEventListener('change', (e) => {\n    sub.hidden = !e.detail.checked;\n  });\n</script>\n",
    "react": "import '@ahaslides-product/design/icons';                 // <aha-icon> — the header \"?\" help glyph + row controls\nimport '@ahaslides-product/design/aha-setting-group';     // registers <aha-setting-group>\nimport '@ahaslides-product/design/aha-sub-setting-group'; // registers <aha-sub-setting-group>\nimport '@ahaslides-product/design/aha-settings-list';     // <aha-settings-item> rows\nimport '@ahaslides-product/design/aha-switch';\nimport '@ahaslides-product/design/aha-input';\nimport { useState } from 'react';\n\n// <aha-setting-group> bakes in the spacing scale: rows 16px apart, groups 32px apart automatically,\n// tone=\"danger\" 48px down — no dividers, no cards. Put guidance in `help` (the \"?\" tooltip), an\n// action in the `action` slot, and dependent settings in a nested <aha-sub-setting-group> that you\n// hide when the parent is off.\nfunction DeckSettings() {\n  const [timerOn, setTimerOn] = useState(true);\n  return (\n    <div style={{ maxWidth: 380 }}>\n      <aha-setting-group label=\"Presentation\" help=\"How the deck shows to the audience.\">\n        <aha-settings-item label=\"Progress bar\">\n          <aha-switch slot=\"control\" checked=\"\" />\n        </aha-settings-item>\n\n        <aha-settings-item label=\"Question timer\">\n          <aha-switch slot=\"control\"\n            {...(timerOn ? { checked: '' } : {})}\n            onChange={(e) => setTimerOn(e.detail.checked)} />\n        </aha-settings-item>\n        {/* dependent settings — hidden when the parent toggle is off */}\n        <aha-sub-setting-group {...(timerOn ? {} : { hidden: '' })}>\n          <aha-settings-item label=\"Seconds per question\">\n            <aha-input slot=\"control\" value=\"30\" />\n          </aha-settings-item>\n          <aha-settings-item label=\"Auto-advance\">\n            <aha-switch slot=\"control\" />\n          </aha-settings-item>\n        </aha-sub-setting-group>\n      </aha-setting-group>\n\n      {/* Group 2 — no wiring: it sits 32px below automatically. */}\n      <aha-setting-group label=\"Audience\">\n        <aha-settings-item label=\"Anonymous join\">\n          <aha-switch slot=\"control\" checked=\"\" />\n        </aha-settings-item>\n      </aha-setting-group>\n    </div>\n  );\n}\n",
    "vue": "// main.ts — register the elements + mark aha-* as custom elements\nimport '@ahaslides-product/design/icons';                 // <aha-icon> — the header \"?\" help glyph + row controls\nimport '@ahaslides-product/design/aha-setting-group';     // registers <aha-setting-group>\nimport '@ahaslides-product/design/aha-sub-setting-group'; // registers <aha-sub-setting-group>\nimport '@ahaslides-product/design/aha-settings-list';     // <aha-settings-item> rows\nimport '@ahaslides-product/design/aha-switch';\nimport '@ahaslides-product/design/aha-input';\napp.config.compilerOptions.isCustomElement = (tag) => tag.startsWith('aha-');\n\n// Component.vue — <aha-setting-group> bakes in the spacing scale (rows 16 · groups 32 · danger 48).\n// Guidance goes in `help` (the \"?\" tooltip); dependent settings nest in <aha-sub-setting-group>,\n// hidden when the parent is off.\n<script setup>\nimport { ref } from 'vue';\nconst timerOn = ref(true);\n</script>\n\n<template>\n  <div style=\"max-width:380px\">\n    <aha-setting-group label=\"Presentation\" help=\"How the deck shows to the audience.\">\n      <aha-settings-item label=\"Progress bar\">\n        <aha-switch slot=\"control\" checked />\n      </aha-settings-item>\n\n      <aha-settings-item label=\"Question timer\">\n        <aha-switch slot=\"control\" :checked.prop=\"timerOn\"\n          @change=\"timerOn = $event.detail.checked\" />\n      </aha-settings-item>\n      <!-- dependent settings — hidden when the parent toggle is off -->\n      <aha-sub-setting-group :hidden=\"!timerOn\">\n        <aha-settings-item label=\"Seconds per question\">\n          <aha-input slot=\"control\" value=\"30\" />\n        </aha-settings-item>\n        <aha-settings-item label=\"Auto-advance\">\n          <aha-switch slot=\"control\" />\n        </aha-settings-item>\n      </aha-sub-setting-group>\n    </aha-setting-group>\n\n    <!-- Group 2 — no wiring: it sits 32px below automatically. -->\n    <aha-setting-group label=\"Audience\">\n      <aha-settings-item label=\"Anonymous join\">\n        <aha-switch slot=\"control\" checked />\n      </aha-settings-item>\n    </aha-setting-group>\n  </div>\n</template>\n"
  }
}
