Toggle Setting List
blocklayoutList of toggle-able settings in a SectionCard. Spell rows out inline with ToggleSettingRow — each row is a controlled switch taking `checked` + `onCheckedChange`.
Installation
$pnpm dlx shadcn@latest add https://uipkge.dev/r/lit/toggle-setting-list.json$npx shadcn@latest add https://uipkge.dev/r/lit/toggle-setting-list.json$yarn dlx shadcn@latest add https://uipkge.dev/r/lit/toggle-setting-list.json$bunx shadcn@latest add https://uipkge.dev/r/lit/toggle-setting-list.jsonManifest:
https://uipkge.dev/r/lit/toggle-setting-list.jsonInstalls to:src/uip/blocks/toggle-setting-list/Variants
Loading interactive previews…
Loading interactive previews…
Props
| Name | Type / Values | Default | Required |
|---|---|---|---|
heading | string | Notifications | optional |
description | string | — | optional |
Schema
Type aliases exported from this item's source. Use these to shape the data you pass in.
HTMLElementTagNameMapinterface HTMLElementTagNameMap {
'uip-toggle-setting-list': UipToggleSettingList
'uip-toggle-setting-row': UipToggleSettingRow
}
}npm dependencies
Includes
Files installed (1)
src/uip/blocks/toggle-setting-list/toggle-setting-list.ts4.3 kB
import { LitElement, css, html, nothing } from 'lit' import { cn } from '../../lib/utils' import { tailwind } from '../../lib/styles' import { ThemeController } from '../../lib/theme' // Side-effect import: registers <uip-section-card> for standalone use // (consumers who install only this block still get a working card). import '../../components/section-card/section-card' /** * <uip-toggle-setting-list> — the registry ToggleSettingList block as a web component. * * Class strings are React's ToggleSettingList verbatim. React's `title` * becomes `heading` (`title` is taken by HTMLElement); `headerIcon` * becomes the `header-icon` slot (forwarded to SectionCard's * `header-action` slot); `children` becomes the default slot (the rows, * rendered inside React's `-my-4 divide-y` list). Rows are * <uip-toggle-setting-row> elements (same file, same install unit). */ export class UipToggleSettingList extends LitElement { static shadowRootOptions = { ...LitElement.shadowRootOptions, delegatesFocus: true } // :host display can't be a utility class (the host has no template of its own). static styles = [tailwind, css`:host { display: block; }`] static properties = { heading: {}, description: {}, } heading = 'Notifications' description?: string constructor() { super() new ThemeController(this) } connectedCallback() { super.connectedCallback() this.setAttribute('data-uipkge', '') this.setAttribute('data-slot', 'toggle-setting-list') } render() { return html` <uip-section-card data-slot="toggle-setting-list" heading=${this.heading} description=${this.description ?? nothing}> <span slot="header-action"><slot name="header-icon"></slot></span> <ul class="-my-4 divide-y"><slot></slot></ul> </uip-section-card> ` } } /** * <uip-toggle-setting-row> — React's ToggleSettingRow: one controlled switch * row. Class strings are React's verbatim (the hand-rolled * `role="switch"` button, not the Switch primitive). `checked` is the live * state; `onCheckedChange` becomes the `checked-change` CustomEvent (detail: * boolean, bubbles, composed). */ export class UipToggleSettingRow extends LitElement { static shadowRootOptions = { ...LitElement.shadowRootOptions, delegatesFocus: true } static styles = [tailwind, css`:host { display: block; }`] static properties = { label: {}, desc: {}, checked: { type: Boolean }, } label = '' desc?: string checked = false constructor() { super() new ThemeController(this) } connectedCallback() { super.connectedCallback() this.setAttribute('data-uipkge', '') this.setAttribute('data-slot', 'toggle-setting-row') } private toggle() { this.checked = !this.checked this.dispatchEvent(new CustomEvent<boolean>('checked-change', { detail: this.checked, bubbles: true, composed: true })) } render() { return html` <li class="flex items-center justify-between gap-4 py-4 first:pt-0"> <div> <p class="text-sm font-medium">${this.label}</p> ${this.desc ? html`<p class="text-muted-foreground text-xs">${this.desc}</p>` : nothing} </div> <button type="button" role="switch" aria-label=${this.label} aria-checked=${this.checked ? 'true' : 'false'} class=${cn( 'focus-visible:ring-ring relative inline-flex h-5 w-9 shrink-0 cursor-pointer rounded-full transition-colors focus:outline-none focus-visible:ring-2', this.checked ? 'bg-primary' : 'bg-muted-foreground/30', )} @click=${this.toggle} > <span class=${cn( 'bg-background inline-block size-4 translate-y-0.5 rounded-full shadow transition-transform', this.checked ? 'translate-x-[18px]' : 'translate-x-0.5', )} ></span> </button> </li> ` } } customElements.get('uip-toggle-setting-list') || customElements.define('uip-toggle-setting-list', UipToggleSettingList) customElements.get('uip-toggle-setting-row') || customElements.define('uip-toggle-setting-row', UipToggleSettingRow) declare global { interface HTMLElementTagNameMap { 'uip-toggle-setting-list': UipToggleSettingList 'uip-toggle-setting-row': UipToggleSettingRow } }
Raw manifest:https://uipkge.dev/r/lit/toggle-setting-list.json