Container
Container primitive for readable measure and horizontal gutters.
Default
With no properties supplied, Container caps its column at a 65ch measure, centers it in the available space, and pads it with default gutters.
Code
<link
rel="component"
href="@threadlabs/looma/components/ui-container/ui-container.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-card/ui-card.html"
>
<ui-container>
<ui-card
padding="sm"
>The Fellowship office memo stays within a readable 65ch measure.</ui-card>
</ui-container><script setup>
import { UiCard, UiContainer } from "@threadlabs/looma";
</script>
<template>
<UiContainer>
<UiCard
padding="sm"
>The Fellowship office memo stays within a readable 65ch measure.</UiCard>
</UiContainer>
</template>import { UiCard, UiContainer } from "@threadlabs/looma";
export default function Example() {
return <UiContainer>
<UiCard
padding="sm"
>The Fellowship office memo stays within a readable 65ch measure.</UiCard>
</UiContainer>;
}/** @jsxImportSource preact */
import { UiCard, UiContainer } from "@threadlabs/looma";
export default function Example() {
return <UiContainer>
<UiCard
padding="sm"
>The Fellowship office memo stays within a readable 65ch measure.</UiCard>
</UiContainer>;
}<script>
import { UiCard, UiContainer } from "@threadlabs/looma";
</script>
<UiContainer>
<UiCard
padding="sm"
>The Fellowship office memo stays within a readable 65ch measure.</UiCard>
</UiContainer>import { Component } from "@angular/core";
import { UiCard, UiContainer } from "@threadlabs/looma";
@Component({
selector: "example-view",
standalone: true,
imports: [UiContainer, UiCard],
template: `
<div
ui-container
>
<ng-template
ui-card
[padding]="'sm'"
>The Fellowship office memo stays within a readable 65ch measure.</ng-template>
</div>
`,
})
export default class Example {}measure="narrow"
The narrow measure caps the column at 45ch; the tinted bands either side are the default gutters.
Code
<link
rel="component"
href="@threadlabs/looma/components/ui-container/ui-container.html"
>
<ui-container
measure="narrow"
>
<div>Narrow 45ch measure</div>
</ui-container><script setup>
import { UiContainer } from "@threadlabs/looma";
</script>
<template>
<UiContainer
measure="narrow"
>
<div>Narrow 45ch measure</div>
</UiContainer>
</template>import { UiContainer } from "@threadlabs/looma";
export default function Example() {
return <UiContainer
measure="narrow"
>
<div>Narrow 45ch measure</div>
</UiContainer>;
}/** @jsxImportSource preact */
import { UiContainer } from "@threadlabs/looma";
export default function Example() {
return <UiContainer
measure="narrow"
>
<div>Narrow 45ch measure</div>
</UiContainer>;
}<script>
import { UiContainer } from "@threadlabs/looma";
</script>
<UiContainer
measure="narrow"
>
<div>Narrow 45ch measure</div>
</UiContainer>import { Component } from "@angular/core";
import { UiContainer } from "@threadlabs/looma";
@Component({
selector: "example-view",
standalone: true,
imports: [UiContainer],
template: `
<div
ui-container
[measure]="'narrow'"
>
<div>Narrow 45ch measure</div>
</div>
`,
})
export default class Example {}gutters="l"
Larger gutters keep content away from the column edges, which matters most when the container is narrower than the measure.
Code
<link
rel="component"
href="@threadlabs/looma/components/ui-container/ui-container.html"
>
<div
style="max-width: 20rem; margin-inline: auto"
>
<ui-container
gutters="l"
>
<div>Large gutters</div>
</ui-container>
</div><script setup>
import { UiContainer } from "@threadlabs/looma";
</script>
<template>
<div
style="max-width: 20rem; margin-inline: auto"
>
<UiContainer
gutters="l"
>
<div>Large gutters</div>
</UiContainer>
</div>
</template>import { UiContainer } from "@threadlabs/looma";
export default function Example() {
return <div
style={{"maxWidth":"20rem","marginInline":"auto"}}
>
<UiContainer
gutters="l"
>
<div>Large gutters</div>
</UiContainer>
</div>;
}/** @jsxImportSource preact */
import { UiContainer } from "@threadlabs/looma";
export default function Example() {
return <div
style={{"maxWidth":"20rem","marginInline":"auto"}}
>
<UiContainer
gutters="l"
>
<div>Large gutters</div>
</UiContainer>
</div>;
}<script>
import { UiContainer } from "@threadlabs/looma";
</script>
<div
style="max-width: 20rem; margin-inline: auto"
>
<UiContainer
gutters="l"
>
<div>Large gutters</div>
</UiContainer>
</div>import { Component } from "@angular/core";
import { UiContainer } from "@threadlabs/looma";
@Component({
selector: "example-view",
standalone: true,
imports: [UiContainer],
template: `
<div
style="max-width: 20rem; margin-inline: auto"
>
<div
ui-container
[gutters]="'l'"
>
<div>Large gutters</div>
</div>
</div>
`,
})
export default class Example {}Bounded reading panel
Fill keeps the readable measure while a nested Scroll Area takes the remaining height. The panel's heading and action stay visible.
Reading notes
A bounded reading panel keeps each line at a comfortable measure.
Longer notes scroll within that panel while the surrounding controls stay in place.
The same container can hold a short note or a longer collection without changing its outer geometry.
Use the panel's available height instead of fixing the height of every paragraph.
Code
<link
rel="component"
href="@threadlabs/looma/components/ui-stack/ui-stack.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-container/ui-container.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-text/ui-text.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-scroll-area/ui-scroll-area.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-cluster/ui-cluster.html"
>
<link
rel="component"
href="@threadlabs/looma/components/ui-button/ui-button.html"
>
<ui-stack
height="240"
>
<ui-container
fill
>
<ui-stack
gap="m"
fill
>
<ui-text
as="h3"
weight="semibold"
>Reading notes</ui-text>
<ui-scroll-area
fill
tabindex="0"
role="region"
aria-label="Reading notes"
>
<ui-stack
gap="m"
>
<ui-text>A bounded reading panel keeps each line at a comfortable measure.</ui-text>
<ui-text>Longer notes scroll within that panel while the surrounding controls stay in place.</ui-text>
<ui-text>The same container can hold a short note or a longer collection without changing its outer geometry.</ui-text>
<ui-text>Use the panel's available height instead of fixing the height of every paragraph.</ui-text>
</ui-stack>
</ui-scroll-area>
<ui-cluster
justify="end"
>
<ui-button
variant="outline"
>Continue</ui-button>
</ui-cluster>
</ui-stack>
</ui-container>
</ui-stack><script setup>
import { UiButton, UiCluster, UiContainer, UiScrollArea, UiStack, UiText } from "@threadlabs/looma";
</script>
<template>
<UiStack
:height="240"
>
<UiContainer
:fill="true"
>
<UiStack
gap="m"
:fill="true"
>
<UiText
as="h3"
weight="semibold"
>Reading notes</UiText>
<UiScrollArea
:fill="true"
tabindex="0"
role="region"
aria-label="Reading notes"
>
<UiStack
gap="m"
>
<UiText>A bounded reading panel keeps each line at a comfortable measure.</UiText>
<UiText>Longer notes scroll within that panel while the surrounding controls stay in place.</UiText>
<UiText>The same container can hold a short note or a longer collection without changing its outer geometry.</UiText>
<UiText>Use the panel's available height instead of fixing the height of every paragraph.</UiText>
</UiStack>
</UiScrollArea>
<UiCluster
justify="end"
>
<UiButton
variant="outline"
>Continue</UiButton>
</UiCluster>
</UiStack>
</UiContainer>
</UiStack>
</template>import { UiButton, UiCluster, UiContainer, UiScrollArea, UiStack, UiText } from "@threadlabs/looma";
export default function Example() {
return <UiStack
height={240}
>
<UiContainer
fill
>
<UiStack
gap="m"
fill
>
<UiText
as="h3"
weight="semibold"
>Reading notes</UiText>
<UiScrollArea
fill
tabIndex="0"
role="region"
aria-label="Reading notes"
>
<UiStack
gap="m"
>
<UiText>A bounded reading panel keeps each line at a comfortable measure.</UiText>
<UiText>Longer notes scroll within that panel while the surrounding controls stay in place.</UiText>
<UiText>The same container can hold a short note or a longer collection without changing its outer geometry.</UiText>
<UiText>Use the panel's available height instead of fixing the height of every paragraph.</UiText>
</UiStack>
</UiScrollArea>
<UiCluster
justify="end"
>
<UiButton
variant="outline"
>Continue</UiButton>
</UiCluster>
</UiStack>
</UiContainer>
</UiStack>;
}/** @jsxImportSource preact */
import { UiButton, UiCluster, UiContainer, UiScrollArea, UiStack, UiText } from "@threadlabs/looma";
export default function Example() {
return <UiStack
height={240}
>
<UiContainer
fill
>
<UiStack
gap="m"
fill
>
<UiText
as="h3"
weight="semibold"
>Reading notes</UiText>
<UiScrollArea
fill
tabIndex="0"
role="region"
aria-label="Reading notes"
>
<UiStack
gap="m"
>
<UiText>A bounded reading panel keeps each line at a comfortable measure.</UiText>
<UiText>Longer notes scroll within that panel while the surrounding controls stay in place.</UiText>
<UiText>The same container can hold a short note or a longer collection without changing its outer geometry.</UiText>
<UiText>Use the panel's available height instead of fixing the height of every paragraph.</UiText>
</UiStack>
</UiScrollArea>
<UiCluster
justify="end"
>
<UiButton
variant="outline"
>Continue</UiButton>
</UiCluster>
</UiStack>
</UiContainer>
</UiStack>;
}<script>
import { UiButton, UiCluster, UiContainer, UiScrollArea, UiStack, UiText } from "@threadlabs/looma";
</script>
<UiStack
height={240}
>
<UiContainer
fill
>
<UiStack
gap="m"
fill
>
<UiText
as="h3"
weight="semibold"
>Reading notes</UiText>
<UiScrollArea
fill
tabindex="0"
role="region"
aria-label="Reading notes"
>
<UiStack
gap="m"
>
<UiText>A bounded reading panel keeps each line at a comfortable measure.</UiText>
<UiText>Longer notes scroll within that panel while the surrounding controls stay in place.</UiText>
<UiText>The same container can hold a short note or a longer collection without changing its outer geometry.</UiText>
<UiText>Use the panel's available height instead of fixing the height of every paragraph.</UiText>
</UiStack>
</UiScrollArea>
<UiCluster
justify="end"
>
<UiButton
variant="outline"
>Continue</UiButton>
</UiCluster>
</UiStack>
</UiContainer>
</UiStack>import { Component } from "@angular/core";
import { UiButton, UiCluster, UiContainer, UiScrollArea, UiStack, UiText } from "@threadlabs/looma";
@Component({
selector: "example-view",
standalone: true,
imports: [UiStack, UiContainer, UiText, UiScrollArea, UiCluster, UiButton],
template: `
<div
ui-stack
[height]="240"
>
<div
ui-container
[fill]="true"
>
<div
ui-stack
[gap]="'m'"
[fill]="true"
>
<ng-template
ui-text
[as]="'h3'"
[weight]="'semibold'"
>Reading notes</ng-template>
<div
ui-scroll-area
[fill]="true"
tabindex="0"
role="region"
aria-label="Reading notes"
>
<div
ui-stack
[gap]="'m'"
>
<ng-template
ui-text
>A bounded reading panel keeps each line at a comfortable measure.</ng-template>
<ng-template
ui-text
>Longer notes scroll within that panel while the surrounding controls stay in place.</ng-template>
<ng-template
ui-text
>The same container can hold a short note or a longer collection without changing its outer geometry.</ng-template>
<ng-template
ui-text
>Use the panel's available height instead of fixing the height of every paragraph.</ng-template>
</div>
</div>
<div
ui-cluster
[justify]="'end'"
>
<ng-template
ui-button
[variant]="'outline'"
>Continue</ng-template>
</div>
</div>
</div>
</div>
`,
})
export default class Example {}API
Package: @threadlabs/looma · Native root: div
Attributes
| Name | Description | Property | Type | Default | Allowed values |
|---|---|---|---|---|---|
fill | Keeps the readable width while filling available layout space. Uses a flex column so scrolling children can shrink inside a bounded flex or grid parent. Omit it to keep the usual block layout. | fill | boolean | false | — |
gutters | Inline padding on both sides, which keeps content off the edges of a narrow screen: s is 0.75rem, m is 1rem (also the default), and l is 1.5rem. | gutters | keyword | — | s, m, l |
measure | The container's maximum width, in characters of the current font: narrow is 45ch, wide is 80ch, and unset is 65ch, a comfortable reading line. The container centres itself when its parent is wider. The --ui-container-measure custom property, set on :root, an ancestor, or the container itself, overrides it. | measure | keyword | — | narrow, wide |
Framework props
| Name | Type | Default | Allowed values |
|---|---|---|---|
fill | boolean | false | — |
gutters | "s" | "m" | "l" | — | s, m, l |
measure | "narrow" | "wide" | — | narrow, wide |
Events
No events.
Slots
| Name | Purpose |
|---|---|
default | Default child content. |
Design tokens
Set shared theme properties on a theme boundary. Component hooks apply only to their owning component.
Component tokens
| Token | Declared values | Fallback |
|---|---|---|
--ui-container-gutters | var(--ui-space-4) | var(--ui-space-3) | var(--ui-space-5) | — |
--ui-container-measure | 65ch | 45ch | 80ch | — |
Shared tokens
| Token | Fallback |
|---|---|
--ui-space-3 | — |
--ui-space-4 | — |
--ui-space-5 | — |