Patterns · Settings
Sub setting group
The dependent (child) settings wrapper — indents a cluster of sub-settings under one parent toggle with a tight gap, spacing only (no border, no card).
Examples
Parent
Dependent (child) settings · 8px above (binds tighter than the 16 between siblings) · 24px indent · host owns visibility (hidden when the parent is off) · no border/card
<!-- Paste-and-run: save as .html and open in a browser. No build step.
<aha-sub-setting-group> is the SAME shared custom element React and Vue consume — here in its
native form. It nests DEPENDENT settings under a parent toggle: 8px above (binds tighter than
the 16 between siblings) + a 24px indent — no left border, no card. The host owns visibility:
add `hidden` when the parent is off. Theming comes only from the --aha-* tokens in tokens.css. -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/tokens.css">
<script type="module">
import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/icons.js'; // <aha-icon> — row control glyphs
import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/aha-setting-group.js'; // registers <aha-setting-group> (the parent group)
import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/aha-sub-setting-group.js'; // registers <aha-sub-setting-group>
import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/aha-settings-list.js'; // <aha-settings-item> rows
import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/aha-switch.js'; // reused row control
import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/aha-input.js'; // reused row control
</script>
<div style="max-width:380px">
<aha-setting-group label="Question timer">
<!-- the parent toggle -->
<aha-settings-item label="Show a timer">
<aha-switch slot="control" id="parent" checked></aha-switch>
</aha-settings-item>
<!-- its dependent sub-settings — indented 24px, bound 8px under the parent, hidden when off -->
<aha-sub-setting-group id="sub">
<aha-settings-item label="Seconds per question">
<aha-input slot="control" value="30"></aha-input>
</aha-settings-item>
<aha-settings-item label="Auto-advance when time's up">
<aha-switch slot="control"></aha-switch>
</aha-settings-item>
</aha-sub-setting-group>
</aha-setting-group>
</div>
<script>
// Host owns visibility: collapse the dependent sub-settings when the parent is off.
const sub = document.getElementById('sub');
document.getElementById('parent').addEventListener('change', (e) => {
sub.hidden = !e.detail.checked;
});
</script>
import '@ahaslides-product/design/icons'; // <aha-icon> — row control glyphs
import '@ahaslides-product/design/aha-setting-group'; // the parent group
import '@ahaslides-product/design/aha-sub-setting-group'; // registers <aha-sub-setting-group>
import '@ahaslides-product/design/aha-settings-list'; // <aha-settings-item> rows
import '@ahaslides-product/design/aha-switch';
import '@ahaslides-product/design/aha-input';
import { useState } from 'react';
// <aha-sub-setting-group> nests DEPENDENT settings under a parent toggle: 8px above + 24px indent,
// spacing only (no border, no card). The host owns visibility — add `hidden` when the parent is off.
function TimerSettings() {
const [on, setOn] = useState(true);
return (
<div style={{ maxWidth: 380 }}>
<aha-setting-group label="Question timer">
<aha-settings-item label="Show a timer">
<aha-switch slot="control"
{...(on ? { checked: '' } : {})}
onChange={(e) => setOn(e.detail.checked)} />
</aha-settings-item>
{/* dependent sub-settings — hidden when the parent is off */}
<aha-sub-setting-group {...(on ? {} : { hidden: '' })}>
<aha-settings-item label="Seconds per question">
<aha-input slot="control" value="30" />
</aha-settings-item>
<aha-settings-item label="Auto-advance when time's up">
<aha-switch slot="control" />
</aha-settings-item>
</aha-sub-setting-group>
</aha-setting-group>
</div>
);
}
// main.ts — register the elements + mark aha-* as custom elements
import '@ahaslides-product/design/icons'; // <aha-icon> — row control glyphs
import '@ahaslides-product/design/aha-setting-group'; // the parent group
import '@ahaslides-product/design/aha-sub-setting-group'; // registers <aha-sub-setting-group>
import '@ahaslides-product/design/aha-settings-list'; // <aha-settings-item> rows
import '@ahaslides-product/design/aha-switch';
import '@ahaslides-product/design/aha-input';
app.config.compilerOptions.isCustomElement = (tag) => tag.startsWith('aha-');
// Component.vue — <aha-sub-setting-group> nests DEPENDENT settings under a parent toggle: 8px above
// + 24px indent, spacing only. The host owns visibility — bind `hidden` off the parent state.
<script setup>
import { ref } from 'vue';
const on = ref(true);
</script>
<template>
<div style="max-width:380px">
<aha-setting-group label="Question timer">
<aha-settings-item label="Show a timer">
<aha-switch slot="control" :checked.prop="on"
@change="on = $event.detail.checked" />
</aha-settings-item>
<!-- dependent sub-settings — hidden when the parent is off -->
<aha-sub-setting-group :hidden="!on">
<aha-settings-item label="Seconds per question">
<aha-input slot="control" value="30" />
</aha-settings-item>
<aha-settings-item label="Auto-advance when time's up">
<aha-switch slot="control" />
</aha-settings-item>
</aha-sub-setting-group>
</aha-setting-group>
</div>
</template>
API
| Prop | Type | Default | Notes |
|---|---|---|---|
hidden | boolean | false | Author-controlled: collapse the sub-settings when the parent setting is off (the component does not derive this itself) |
(default slot) | slot | — | The dependent sub-settings; they stack 16px apart, indented 24px under the parent |
Install
# .npmrc — once: point the @ahaslides-product scope at GitHub Packages
@ahaslides-product:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN} # a GitHub token with read:packages
npm i @ahaslides-product/design
import '@ahaslides-product/design/tokens.css'; // once, at the app root
import '@ahaslides-product/design/aha-sub-setting-group'; // registers <aha-sub-setting-group>
Agent feed for this component (absolute, fetchable anywhere): sub-setting-group.agent.json · sub-setting-group.md · sub-setting-group.llms.txt
When to use
When to use
- Sub setting group — settings that only apply when a parent toggle is on — indent them under it and hide when off
- Setting group — a top-level titled cluster of settings (the 16/32/48 scale + optional header)
- a disabled row — the setting always shows but isn't currently changeable — dim it, don't nest it
Use this only for genuinely dependent settings — ones that are meaningless until a parent is on. Keep the parent row and its sub-group inside the same setting group. Hide (not disable) the sub-settings when the parent is off, so the panel doesn't fill with dead controls. Never draw a left rail or box around the nest — the 24px indent + the tight 8px bind are the whole signal.
Surfaces
editor settings dashboard
Spec
Bind margin-top 8px — tighter than the 16 between siblings, so the child binds to its parent · Indent padding-left 24px — the primary nesting signal (no left border, no card) · Rows column · 16px between dependent sub-settings (the settings scale) · Visibility host owns it — author adds `hidden` when the parent is off (:host([hidden]){display:none}) · Structure no divider lines, no card/box — spacing + indent only