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.

Profile

The details people see when you work together.

Notifications

Choose which updates you receive.

Delete account

Permanently remove this account and its saved preferences.

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

NameDescriptionPropertyTypeDefaultAllowed values
headingThe section's heading, an h2. Leave it empty for a section with no visible heading, and name the section with aria-label.headingstring—
tonedanger marks a section of destructive actions (a danger zone): its heading and a framed section's border take the danger colour.tonekeywordneutralneutral, danger
variantHow 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.variantkeywordplainplain, card, divided, fieldset

Framework props

NameTypeDefaultAllowed values
headingstring—
tone"neutral" | "danger"neutralneutral, danger
variant"plain" | "card" | "divided" | "fieldset"plainplain, card, divided, fieldset

Events

No events.

Slots

NamePurpose
descriptionNamed content for the description region.
actionsNamed content for the actions region.
defaultDefault 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

TokenFallback
--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-displayinherit
--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—