Stack

Vertical layout primitive that owns spacing between children.

Default

With no properties supplied, Stack uses its default gap, alignment, and distribution.

Frodo
Sam
Sméagol

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-stack/ui-stack.html"
>
<link
  rel="component"
  href="@threadlabs/looma/components/ui-card/ui-card.html"
>

<ui-stack>
  <ui-card
    padding="sm"
  >Frodo</ui-card>
  <ui-card
    padding="sm"
  >Sam</ui-card>
  <ui-card
    padding="sm"
  >Sméagol</ui-card>
</ui-stack>
<script setup>
  import { UiCard, UiStack } from "@threadlabs/looma";
</script>

<template>
  <UiStack>
    <UiCard
      padding="sm"
    >Frodo</UiCard>
    <UiCard
      padding="sm"
    >Sam</UiCard>
    <UiCard
      padding="sm"
    >Sméagol</UiCard>
  </UiStack>
</template>
import { UiCard, UiStack } from "@threadlabs/looma";

export default function Example() {
  return <UiStack>
    <UiCard
      padding="sm"
    >Frodo</UiCard>
    <UiCard
      padding="sm"
    >Sam</UiCard>
    <UiCard
      padding="sm"
    >Sméagol</UiCard>
  </UiStack>;
}
/** @jsxImportSource preact */
import { UiCard, UiStack } from "@threadlabs/looma";

export default function Example() {
  return <UiStack>
    <UiCard
      padding="sm"
    >Frodo</UiCard>
    <UiCard
      padding="sm"
    >Sam</UiCard>
    <UiCard
      padding="sm"
    >Sméagol</UiCard>
  </UiStack>;
}
<script>
  import { UiCard, UiStack } from "@threadlabs/looma";
</script>

<UiStack>
  <UiCard
    padding="sm"
  >Frodo</UiCard>
  <UiCard
    padding="sm"
  >Sam</UiCard>
  <UiCard
    padding="sm"
  >Sméagol</UiCard>
</UiStack>
import { Component } from "@angular/core";
import { UiCard, UiStack } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiStack, UiCard],
  template: `
    <div
      ui-stack
    >
      <ng-template
        ui-card
        [padding]="'sm'"
      >Frodo</ng-template>
      <ng-template
        ui-card
        [padding]="'sm'"
      >Sam</ng-template>
      <ng-template
        ui-card
        [padding]="'sm'"
      >Sméagol</ng-template>
    </div>
  `,
})
export default class Example {}

gap="xl" and align="center"

The extra-large gap visibly increases vertical space; center alignment returns the bounded children to their intrinsic widths.

Frodo
Sam
Sméagol

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-stack/ui-stack.html"
>
<link
  rel="component"
  href="@threadlabs/looma/components/ui-card/ui-card.html"
>

<ui-stack
  gap="xl"
  align="center"
>
  <ui-card
    padding="sm"
  >Frodo</ui-card>
  <ui-card
    padding="sm"
  >Sam</ui-card>
  <ui-card
    padding="sm"
  >Sméagol</ui-card>
</ui-stack>
<script setup>
  import { UiCard, UiStack } from "@threadlabs/looma";
</script>

<template>
  <UiStack
    gap="xl"
    align="center"
  >
    <UiCard
      padding="sm"
    >Frodo</UiCard>
    <UiCard
      padding="sm"
    >Sam</UiCard>
    <UiCard
      padding="sm"
    >Sméagol</UiCard>
  </UiStack>
</template>
import { UiCard, UiStack } from "@threadlabs/looma";

export default function Example() {
  return <UiStack
    gap="xl"
    align="center"
  >
    <UiCard
      padding="sm"
    >Frodo</UiCard>
    <UiCard
      padding="sm"
    >Sam</UiCard>
    <UiCard
      padding="sm"
    >Sméagol</UiCard>
  </UiStack>;
}
/** @jsxImportSource preact */
import { UiCard, UiStack } from "@threadlabs/looma";

export default function Example() {
  return <UiStack
    gap="xl"
    align="center"
  >
    <UiCard
      padding="sm"
    >Frodo</UiCard>
    <UiCard
      padding="sm"
    >Sam</UiCard>
    <UiCard
      padding="sm"
    >Sméagol</UiCard>
  </UiStack>;
}
<script>
  import { UiCard, UiStack } from "@threadlabs/looma";
</script>

<UiStack
  gap="xl"
  align="center"
>
  <UiCard
    padding="sm"
  >Frodo</UiCard>
  <UiCard
    padding="sm"
  >Sam</UiCard>
  <UiCard
    padding="sm"
  >Sméagol</UiCard>
</UiStack>
import { Component } from "@angular/core";
import { UiCard, UiStack } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiStack, UiCard],
  template: `
    <div
      ui-stack
      [gap]="'xl'"
      [align]="'center'"
    >
      <ng-template
        ui-card
        [padding]="'sm'"
      >Frodo</ng-template>
      <ng-template
        ui-card
        [padding]="'sm'"
      >Sam</ng-template>
      <ng-template
        ui-card
        [padding]="'sm'"
      >Sméagol</ng-template>
    </div>
  `,
})
export default class Example {}

justify="between"

Justify distributes children along the stack's height when it is taller than its content; between pushes the first and last to the ends.

Top
Bottom

Code

<link
  rel="component"
  href="@threadlabs/looma/components/ui-stack/ui-stack.html"
>

<ui-stack
  justify="between"
  style="height: 12rem"
>
  <div>Top</div>
  <div>Bottom</div>
</ui-stack>
<script setup>
  import { UiStack } from "@threadlabs/looma";
</script>

<template>
  <UiStack
    justify="between"
    style="height: 12rem"
  >
    <div>Top</div>
    <div>Bottom</div>
  </UiStack>
</template>
import { UiStack } from "@threadlabs/looma";

export default function Example() {
  return <UiStack
    justify="between"
    style={{"height":"12rem"}}
  >
    <div>Top</div>
    <div>Bottom</div>
  </UiStack>;
}
/** @jsxImportSource preact */
import { UiStack } from "@threadlabs/looma";

export default function Example() {
  return <UiStack
    justify="between"
    style={{"height":"12rem"}}
  >
    <div>Top</div>
    <div>Bottom</div>
  </UiStack>;
}
<script>
  import { UiStack } from "@threadlabs/looma";
</script>

<UiStack
  justify="between"
  style="height: 12rem"
>
  <div>Top</div>
  <div>Bottom</div>
</UiStack>
import { Component } from "@angular/core";
import { UiStack } from "@threadlabs/looma";

@Component({
  selector: "example-view",
  standalone: true,
  imports: [UiStack],
  template: `
    <div
      ui-stack
      [justify]="'between'"
      style="height: 12rem"
    >
      <div>Top</div>
      <div>Bottom</div>
    </div>
  `,
})
export default class Example {}

API

Package: @threadlabs/looma · Native root: div

Attributes

NameDescriptionPropertyTypeDefaultAllowed values
alignHow items sit across the stack: stretch (the default) makes each fill the stack's width; start, center, and end keep each at its own width, against the start, in the middle, or against the end.alignkeyword—start, center, end, stretch
fillGrows into the remaining space of a flex layout and allows its scrolling children to shrink.fillbooleanfalse—
gapSpace between items, on the spacing scale: none is zero, xs is 0.5rem, s 0.75rem, m 1rem (also the default), l 1.5rem, and xl 2rem. The --ui-stack-gap custom property, set on :root, an ancestor, or the component itself, overrides it. Theme rhythm scales these vertical gaps, while an explicit gap override stays exact.gapkeyword—none, xs, s, m, l, xl
heightAn optional measured height in CSS pixels, for a viewport-bounded composition. Omit it to retain intrinsic sizing.heightnumber——
justifyWhere items sit along a stack that is taller than its content: start (the default), center, end, or between, which spreads the spare space between items. It has no effect unless the stack is given a height or stretched to one.justifykeyword—start, center, end, between

Framework props

NameTypeDefaultAllowed values
align"start" | "center" | "end" | "stretch"—start, center, end, stretch
fillbooleanfalse—
gap"none" | "xs" | "s" | "m" | "l" | "xl"—none, xs, s, m, l, xl
heightnumber——
justify"start" | "center" | "end" | "between"—start, center, end, between

Events

No events.

Slots

NamePurpose
defaultDefault child content.

Design tokens

Set shared theme properties on a theme boundary. Component hooks apply only to their owning component.

Component tokens

TokenDeclared valuesFallback
--ui-stack-gap—calc(var(--_layout-gap) * clamp(0.75, var(--ui-rhythm, 1), 1.5))

Shared tokens

TokenFallback
--ui-rhythm1
--ui-space-2—
--ui-space-3—
--ui-space-4—
--ui-space-5—
--ui-space-6—