Section
A part of a view: an h2 heading, an optional description, actions for the whole section, and its content. variant="fieldset" joins the heading to a rounded frame with a native legend, for a named settings group. Its description and actions stay inside the frame; long headings wrap without covering the content. variant="card" sets it on a bordered surface; variant="divided" rules it off from the section before, for a long form; tone="danger" marks destructive actions. A fieldset is announced as a group named by its legend. Use aria-label when omitting the heading. Space sections with a Stack. Danger fieldsets keep the neutral surface and rounded geometry, using heading and border color to mark destructive actions.
Plain
A heading and its content in the flow of the page.
Recently updated
Pages edited in this workspace, newest first.
Code
<link
rel="component"
href="@threadlabs/looma/components/ui-section/ui-section.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-text/ui-text.html"
>
<ui-section
heading="Recently updated"
>
<ui-text
tone="secondary"
>Pages edited in this workspace, newest first.</ui-text>
</ui-section><script setup>
import { UiSection, UiText } from "@threadlabs/looma";
</script>
<template>
<UiSection
heading="Recently updated"
>
<UiText
tone="secondary"
>Pages edited in this workspace, newest first.</UiText>
</UiSection>
</template>import { UiSection, UiText } from "@threadlabs/looma";
export default function Example() {
return <UiSection
heading="Recently updated"
>
<UiText
tone="secondary"
>Pages edited in this workspace, newest first.</UiText>
</UiSection>;
}/** @jsxImportSource preact */
import { UiSection, UiText } from "@threadlabs/looma";
export default function Example() {
return <UiSection
heading="Recently updated"
>
<UiText
tone="secondary"
>Pages edited in this workspace, newest first.</UiText>
</UiSection>;
}<script>
import { UiSection, UiText } from "@threadlabs/looma";
</script>
<UiSection
heading="Recently updated"
>
<UiText
tone="secondary"
>Pages edited in this workspace, newest first.</UiText>
</UiSection>import { Component } from "@angular/core";
import { UiSection, UiText } from "@threadlabs/looma";
@Component({
selector: "example-view",
standalone: true,
imports: [UiSection, UiText],
template: `
<ng-template
ui-section
[heading]="'Recently updated'"
>
<ng-template
ui-text
[tone]="'secondary'"
>Pages edited in this workspace, newest first.</ng-template>
</ng-template>
`,
})
export default class Example {}Cards and danger
A card groups settings on a surface; danger gives consequential actions a soft warning surface and leading edge.
Profile
How people see you in this site.Ada Lovelace
Delete this site
Everything in it is deleted for everyone.
Code
<link
rel="component"
href="@threadlabs/looma/components/ui-stack/ui-stack.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-section/ui-section.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-text/ui-text.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-button/ui-button.html"
>
<ui-stack
gap="l"
>
<ui-section
heading="Profile"
variant="card"
>
<span
slot="description"
>How people see you in this site.</span>
<ui-text>Ada Lovelace</ui-text>
</ui-section>
<ui-section
heading="Delete this site"
variant="card"
tone="danger"
>
<ui-button
slot="actions"
size="sm"
variant="solid"
tone="danger"
>Delete site</ui-button>
<ui-text
tone="secondary"
size="sm"
>Everything in it is deleted for everyone.</ui-text>
</ui-section>
</ui-stack><script setup>
import { UiButton, UiSection, UiStack, UiText } from "@threadlabs/looma";
</script>
<template>
<UiStack
gap="l"
>
<UiSection
heading="Profile"
variant="card"
>
<template #description>
<span>How people see you in this site.</span>
</template>
<UiText>Ada Lovelace</UiText>
</UiSection>
<UiSection
heading="Delete this site"
variant="card"
tone="danger"
>
<template #actions>
<UiButton
size="sm"
variant="solid"
tone="danger"
>Delete site</UiButton>
</template>
<UiText
tone="secondary"
size="sm"
>Everything in it is deleted for everyone.</UiText>
</UiSection>
</UiStack>
</template>import { UiButton, UiSection, UiStack, UiText } from "@threadlabs/looma";
export default function Example() {
return <UiStack
gap="l"
>
<UiSection
heading="Profile"
variant="card"
slots={{
description: <span>How people see you in this site.</span>,
}}
>
<UiText>Ada Lovelace</UiText>
</UiSection>
<UiSection
heading="Delete this site"
variant="card"
tone="danger"
slots={{
actions: <UiButton
size="sm"
variant="solid"
tone="danger"
>Delete site</UiButton>,
}}
>
<UiText
tone="secondary"
size="sm"
>Everything in it is deleted for everyone.</UiText>
</UiSection>
</UiStack>;
}/** @jsxImportSource preact */
import { UiButton, UiSection, UiStack, UiText } from "@threadlabs/looma";
export default function Example() {
return <UiStack
gap="l"
>
<UiSection
heading="Profile"
variant="card"
slots={{
description: <span>How people see you in this site.</span>,
}}
>
<UiText>Ada Lovelace</UiText>
</UiSection>
<UiSection
heading="Delete this site"
variant="card"
tone="danger"
slots={{
actions: <UiButton
size="sm"
variant="solid"
tone="danger"
>Delete site</UiButton>,
}}
>
<UiText
tone="secondary"
size="sm"
>Everything in it is deleted for everyone.</UiText>
</UiSection>
</UiStack>;
}<script>
import { UiButton, UiSection, UiStack, UiText } from "@threadlabs/looma";
</script>
{#snippet description()}
<span>How people see you in this site.</span>
{/snippet}
{#snippet actions()}
<UiButton
size="sm"
variant="solid"
tone="danger"
>Delete site</UiButton>
{/snippet}
<UiStack
gap="l"
>
<UiSection
heading="Profile"
variant="card"
slots={{ description }}
>
<UiText>Ada Lovelace</UiText>
</UiSection>
<UiSection
heading="Delete this site"
variant="card"
tone="danger"
slots={{ actions }}
>
<UiText
tone="secondary"
size="sm"
>Everything in it is deleted for everyone.</UiText>
</UiSection>
</UiStack>import { Component } from "@angular/core";
import { UiButton, UiSection, UiStack, UiText } from "@threadlabs/looma";
@Component({
selector: "example-view",
standalone: true,
imports: [UiStack, UiSection, UiText, UiButton],
template: `
<div
ui-stack
[gap]="'l'"
>
<ng-template #description>
<span>How people see you in this site.</span>
</ng-template>
<ng-template
ui-section
[heading]="'Profile'"
[variant]="'card'"
[slots]="{ description: description }"
>
<ng-template
ui-text
>Ada Lovelace</ng-template>
</ng-template>
<ng-template #actions>
<ng-template
ui-button
[size]="'sm'"
[variant]="'solid'"
[tone]="'danger'"
>Delete site</ng-template>
</ng-template>
<ng-template
ui-section
[heading]="'Delete this site'"
[variant]="'card'"
[tone]="'danger'"
[slots]="{ actions: actions }"
>
<ng-template
ui-text
[tone]="'secondary'"
[size]="'sm'"
>Everything in it is deleted for everyone.</ng-template>
</ng-template>
</div>
`,
})
export default class Example {}Connected headings
A native legend joins the heading to the frame. Descriptions, actions and fields stay comfortably inside it.
Code
<link
rel="component"
href="@threadlabs/looma/components/ui-stack/ui-stack.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-section/ui-section.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-form-field/ui-form-field.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-input/ui-input.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-button/ui-button.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-text/ui-text.html"
>
<ui-stack
gap="l"
>
<ui-section
heading="Profile"
variant="fieldset"
>
<span
slot="description"
>The details people see when you work together.</span>
<ui-form-field>
<label
slot="label"
for="profile-name"
>Display name</label>
<ui-input
id="profile-name"
value="Ada Lovelace"
></ui-input>
</ui-form-field>
<ui-button
slot="actions"
variant="outline"
tone="accent"
size="sm"
>Reset</ui-button>
</ui-section>
<ui-section
heading="Notifications"
variant="fieldset"
>
<ui-text>Choose which updates you receive.</ui-text>
</ui-section>
<ui-section
heading="Delete account"
variant="fieldset"
tone="danger"
>
<span
slot="description"
>Permanently remove this account and its saved preferences.</span>
<ui-button
slot="actions"
variant="outline"
tone="danger"
>Delete account</ui-button>
</ui-section>
</ui-stack><script setup>
import { UiButton, UiFormField, UiInput, UiSection, UiStack, UiText } from "@threadlabs/looma";
</script>
<template>
<UiStack
gap="l"
>
<UiSection
heading="Profile"
variant="fieldset"
>
<template #description>
<span>The details people see when you work together.</span>
</template>
<UiFormField>
<template #label>
<label
for="profile-name"
>Display name</label>
</template>
<UiInput
id="profile-name"
value="Ada Lovelace"
/>
</UiFormField>
<template #actions>
<UiButton
variant="outline"
tone="accent"
size="sm"
>Reset</UiButton>
</template>
</UiSection>
<UiSection
heading="Notifications"
variant="fieldset"
>
<UiText>Choose which updates you receive.</UiText>
</UiSection>
<UiSection
heading="Delete account"
variant="fieldset"
tone="danger"
>
<template #description>
<span>Permanently remove this account and its saved preferences.</span>
</template>
<template #actions>
<UiButton
variant="outline"
tone="danger"
>Delete account</UiButton>
</template>
</UiSection>
</UiStack>
</template>import { UiButton, UiFormField, UiInput, UiSection, UiStack, UiText } from "@threadlabs/looma";
export default function Example() {
return <UiStack
gap="l"
>
<UiSection
heading="Profile"
variant="fieldset"
slots={{
description: <span>The details people see when you work together.</span>,
actions: <UiButton
variant="outline"
tone="accent"
size="sm"
>Reset</UiButton>,
}}
>
<UiFormField
slots={{
label: <label
htmlFor="profile-name"
>Display name</label>,
}}
>
<UiInput
id="profile-name"
value="Ada Lovelace"
/>
</UiFormField>
</UiSection>
<UiSection
heading="Notifications"
variant="fieldset"
>
<UiText>Choose which updates you receive.</UiText>
</UiSection>
<UiSection
heading="Delete account"
variant="fieldset"
tone="danger"
slots={{
description: <span>Permanently remove this account and its saved preferences.</span>,
actions: <UiButton
variant="outline"
tone="danger"
>Delete account</UiButton>,
}}
>{" "}{" "}{" "}</UiSection>
</UiStack>;
}/** @jsxImportSource preact */
import { UiButton, UiFormField, UiInput, UiSection, UiStack, UiText } from "@threadlabs/looma";
export default function Example() {
return <UiStack
gap="l"
>
<UiSection
heading="Profile"
variant="fieldset"
slots={{
description: <span>The details people see when you work together.</span>,
actions: <UiButton
variant="outline"
tone="accent"
size="sm"
>Reset</UiButton>,
}}
>
<UiFormField
slots={{
label: <label
htmlFor="profile-name"
>Display name</label>,
}}
>
<UiInput
id="profile-name"
value="Ada Lovelace"
/>
</UiFormField>
</UiSection>
<UiSection
heading="Notifications"
variant="fieldset"
>
<UiText>Choose which updates you receive.</UiText>
</UiSection>
<UiSection
heading="Delete account"
variant="fieldset"
tone="danger"
slots={{
description: <span>Permanently remove this account and its saved preferences.</span>,
actions: <UiButton
variant="outline"
tone="danger"
>Delete account</UiButton>,
}}
>{" "}{" "}{" "}</UiSection>
</UiStack>;
}<script>
import { UiButton, UiFormField, UiInput, UiSection, UiStack, UiText } from "@threadlabs/looma";
</script>
{#snippet description()}
<span>The details people see when you work together.</span>
{/snippet}
{#snippet label()}
<label
for="profile-name"
>Display name</label>
{/snippet}
{#snippet actions()}
<UiButton
variant="outline"
tone="accent"
size="sm"
>Reset</UiButton>
{/snippet}
{#snippet sectionDescription()}
<span>Permanently remove this account and its saved preferences.</span>
{/snippet}
{#snippet sectionActions()}
<UiButton
variant="outline"
tone="danger"
>Delete account</UiButton>
{/snippet}
<UiStack
gap="l"
>
<UiSection
heading="Profile"
variant="fieldset"
slots={{ description, actions }}
>
<UiFormField
slots={{ label }}
>
<UiInput
id="profile-name"
value="Ada Lovelace"
/>
</UiFormField>
</UiSection>
<UiSection
heading="Notifications"
variant="fieldset"
>
<UiText>Choose which updates you receive.</UiText>
</UiSection>
<UiSection
heading="Delete account"
variant="fieldset"
tone="danger"
slots={{ description: sectionDescription, actions: sectionActions }}
> </UiSection>
</UiStack>import { Component } from "@angular/core";
import { UiButton, UiFormField, UiInput, UiSection, UiStack, UiText } from "@threadlabs/looma";
@Component({
selector: "example-view",
standalone: true,
imports: [UiStack, UiSection, UiFormField, UiInput, UiButton, UiText],
template: `
<div
ui-stack
[gap]="'l'"
>
<ng-template #description>
<span>The details people see when you work together.</span>
</ng-template>
<ng-template #actions>
<ng-template
ui-button
[variant]="'outline'"
[tone]="'accent'"
[size]="'sm'"
>Reset</ng-template>
</ng-template>
<ng-template
ui-section
[heading]="'Profile'"
[variant]="'fieldset'"
[slots]="{ description: description, actions: actions }"
>
<div
ui-form-field
>
<ng-container ngProjectAs="[slot='label']">
<label
for="profile-name"
>Display name</label>
</ng-container>
<input
ui-input
id="profile-name"
[value]="'Ada Lovelace'"
>
</div>
</ng-template>
<ng-template
ui-section
[heading]="'Notifications'"
[variant]="'fieldset'"
>
<ng-template
ui-text
>Choose which updates you receive.</ng-template>
</ng-template>
<ng-template #sectionDescription>
<span>Permanently remove this account and its saved preferences.</span>
</ng-template>
<ng-template #sectionActions>
<ng-template
ui-button
[variant]="'outline'"
[tone]="'danger'"
>Delete account</ng-template>
</ng-template>
<ng-template
ui-section
[heading]="'Delete account'"
[variant]="'fieldset'"
[tone]="'danger'"
[slots]="{ description: sectionDescription, actions: sectionActions }"
> </ng-template>
</div>
`,
})
export default class Example {}API
Package: @threadlabs/looma · Native root: section
Attributes
| Name | Description | Property | Type | Default | Allowed values |
|---|---|---|---|---|---|
heading | The section's heading, an h2. Leave it empty for a section with no visible heading, and name the section with aria-label. | heading | string | | — |
tone | danger marks a section of destructive actions (a danger zone): its heading and a framed section's border take the danger colour. | tone | keyword | neutral | neutral, danger |
variant | How the section is set apart. plain is a heading and content in the flow of the page; card sits it on a bordered surface, for a settings group; divided rules it off from the section before it, for a long form. fieldset joins the heading to a bordered frame using a native legend. | variant | keyword | plain | plain, card, divided, fieldset |
Framework props
| Name | Type | Default | Allowed values |
|---|---|---|---|
heading | string | | — |
tone | "neutral" | "danger" | neutral | neutral, danger |
variant | "plain" | "card" | "divided" | "fieldset" | plain | plain, card, divided, fieldset |
Events
No events.
Slots
| Name | Purpose |
|---|---|
description | Named content for the description region. |
actions | Named content for the actions region. |
default | Default child content. |
Design tokens
Set shared theme properties on a theme boundary. Component hooks apply only to their owning component.
Component tokens
No component tokens.
Shared tokens
| Token | Fallback |
|---|---|
--ui-accent-line-width | — |
--ui-border-default | — |
--ui-border-divider | — |
--ui-border-strong | — |
--ui-border-width | — |
--ui-danger | — |
--ui-danger-soft | — |
--ui-danger-subtle-text | — |
--ui-font-display | inherit |
--ui-font-semibold | — |
--ui-font-size-lg | — |
--ui-font-size-sm | — |
--ui-line-height | — |
--ui-line-height-tight | — |
--ui-radius-lg | — |
--ui-space-1 | — |
--ui-space-2 | — |
--ui-space-4 | — |
--ui-space-5 | — |
--ui-space-6 | — |
--ui-surface-raised | — |
--ui-text-primary | — |
--ui-text-secondary | — |