Patterns · Settings
Setting Row
ONE setting — a label (with an optional "?" help) plus a slotted DS control; inline (label-left / control-right) by default, or stacked (label above, control full-width) for a wide control.
Examples
Layout
Help
Disabled
Setting row · ONE setting — label + a slotted DS control (the playground drives this one)
Inline (default) · label LEFT · control RIGHT · space-between
Stack · label above · control full-width (a wide textarea / wide select)
<!-- Paste-and-run: save as .html and open in a browser. No build step.
<aha-setting-row> is the SAME shared custom element React and Vue consume — here in its
native form. Theming comes only from the --aha-* tokens in tokens.css. The row ships NO
control of its own — it carries an existing DS control in its `control` slot (reuse). -->
<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'; // registers <aha-icon> (the "?" glyph)
import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/aha-setting-row.js'; // registers <aha-setting-row>
import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/aha-switch.js'; // registers <aha-switch> (a control it carries)
import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/aha-input.js'; // registers <aha-input> (a wide control for the stack layout)
</script>
<!-- inline (default) — label LEFT, control RIGHT -->
<aha-setting-row label="Progress bar">
<aha-switch slot="control" checked></aha-switch>
</aha-setting-row>
<!-- with a "?" help (the circled question glyph) after the label -->
<aha-setting-row label="Leaderboard" help="Shown to the audience between slides.">
<aha-switch slot="control"></aha-switch>
</aha-setting-row>
<!-- stack — label above, control full-width (a wide textarea / wide select) -->
<aha-setting-row label="Speaker notes" layout="stack">
<aha-input slot="control" placeholder="Notes only you can see"></aha-input>
</aha-setting-row>
import '@ahaslides-product/design/icons'; // registers <aha-icon> (the "?" glyph)
import '@ahaslides-product/design/aha-setting-row'; // registers <aha-setting-row>
import '@ahaslides-product/design/aha-switch'; // registers <aha-switch> (a control it carries)
// One shared custom element — React 18 renders it directly (it holds no state of its own).
// `label` is a noun phrase; `help` fills the "?" tooltip; `layout` is 'inline' (default) or 'stack'.
// The row ships NO control — pass an existing DS control in the `control` slot (reuse).
function SettingRow({ label, help, layout, children }) {
return (
<aha-setting-row label={label} {...(help ? { help } : {})} {...(layout ? { layout } : {})}>
{children}
</aha-setting-row>
);
}
// usage — inline (default), label LEFT / control RIGHT
<SettingRow label="Leaderboard" help="Shown to the audience between slides.">
<aha-switch slot="control" />
</SettingRow>
// usage — stack, label above / control full-width
<SettingRow label="Speaker notes" layout="stack">
<aha-input slot="control" placeholder="Notes only you can see" />
</SettingRow>
// main.ts — register the elements + mark aha-* as custom elements
import '@ahaslides-product/design/icons'; // registers <aha-icon> (the "?" glyph)
import '@ahaslides-product/design/aha-setting-row'; // registers <aha-setting-row>
import '@ahaslides-product/design/aha-switch'; // registers <aha-switch> (a control it carries)
import '@ahaslides-product/design/aha-input'; // registers <aha-input> (a wide control for stack)
app.config.compilerOptions.isCustomElement = (tag) => tag.startsWith('aha-');
// Component.vue
<template>
<!-- inline (default) — label LEFT, control RIGHT; help fills the "?" tooltip -->
<aha-setting-row label="Leaderboard" help="Shown to the audience between slides.">
<aha-switch slot="control" />
</aha-setting-row>
<!-- stack — label above, control full-width (a wide textarea / wide select) -->
<aha-setting-row label="Speaker notes" layout="stack">
<aha-input slot="control" placeholder="Notes only you can see" />
</aha-setting-row>
</template>
API
| Prop | Type | Default | Notes |
|---|---|---|---|
label | string | — | The setting name — a noun phrase in sentence case |
help | string | — | Optional guidance — renders the "?" help trigger (circled question glyph) after the label; the tooltip carries the text |
layout | inline | stack | inline | inline: label-left / control-right (space-between). stack: label above, control full-width — for a wide control |
disabled | boolean | false | Dims the label to text-disabled and sets aria-disabled; the slotted control disables itself on its own element |
control | slot | — | The DS control (slot="control") — an existing element like <aha-switch> / <aha-checkbox> / <aha-input>; reuse, never a re-implemented control |
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-setting-row'; // registers <aha-setting-row>
Agent feed for this component (absolute, fetchable anywhere): setting-row.agent.json · setting-row.md · setting-row.llms.txt
When to use
When to use
- Setting row (inline) — a compact control — a switch, a checkbox, a short input — sits to the right of its label
- Setting row (stack) — a wide control — a textarea, a wide select — needs the full row width below the label
- Section header — the title of the GROUP these rows sit under
Name the setting with a noun phrase in sentence case ("Progress bar", "Speaker notes") — never a question and never Title Case. Put guidance in `help` (the "?" tooltip), not a standing line. Choose `inline` for a toggle/checkbox/short input; switch to `stack` the moment the control needs real width (a textarea, a wide select). Never hand-place an icon before the label — functional icons belong inside the control (SETTINGS-40).
Surfaces
editor dashboard settings audience
Spec
Inline row flex; align-items center; justify-content space-between; gap 12; min-height 24 · Label Plus Jakarta 14/21, regular (400), text-default (#1A1A1A); flex:1 (label-left) · Control flex:0 0 auto (control-right); slotted DS control — reuse, not re-implemented · Stack flex-direction column; align-items stretch; gap 8; control full-width · Help optional "?" after the label (DS <aha-tooltip help> — the circled question glyph) · Disabled label dims to text-disabled (#B5B5B5); the control disables itself · Leading icon NONE — no decorative leading-icon slot on the label (SETTINGS-40)