Skip to main content

StackLayout

Places components in one column, top to bottom, with an even gap between them. Use it to build a screen from the kit's components, for example a LocationPath above a few cards.

Loading…
Live editor
<StackLayout gap="sm">
  <LocationPath siteName="My flat" floorName="Level 2" spaceName="Bedroom" />
  <ModuleCard
    name="Climate Module"
    connectionStatus="connected"
    sensors={[
      { metric: "temperature", value: 22.4, unit: "celsius" },
      { metric: "humidity", value: 48, unit: "percent-rh", fractionDigits: 0 },
    ]}
  />
</StackLayout>
Try it

The examples on this page are live. Change the code and the result updates as you type.

StackLayout only adds space between its children. It has no background, border or padding, so you never see it, and you can put it inside any other component, including another StackLayout.

Import​

import { StackLayout } from "@detriz-sh-kit/ui";

The component needs the kit's styles. Load them once, at the root of your app:

import "@detriz-sh-kit/tokens/tokens.css";
import "@detriz-sh-kit/ui/styles.css";

See Installation for how to install the packages.

Basic usage​

Put the components you want to stack inside it:

import { StackLayout, SensorLabel } from "@detriz-sh-kit/ui";

<StackLayout>
<SensorLabel metric="temperature" />
<SensorLabel metric="humidity" />
</StackLayout>;

The examples below leave out the import line. In your app, you need it.

When to use it​

Use StackLayout:

  • as the root of a screen, to stack its sections and cards
  • for a list of cards, like the ModuleCards of a Space
  • inside a card or section, to space out a few smaller components

Don't use it for:

  • Components side by side. Use ColumnLayout.
  • A group with a heading. Use ContentSection.
  • Padding or a background. StackLayout adds neither. The screen or the card around it owns those, so nested stacks never add up extra space.

Gaps​

Use the gap prop. The default is md. The gaps are names, not pixels, so every screen uses the same tested spacing. Each step is double the one before, so nested stacks stay easy to tell apart.

gapSizeUse it when
sm8pxThe children belong closely together, like a LocationPath and its card.
md16pxDefault. Most lists of cards.
lg32pxThe children are separate groups, like two ContentSections.

sm​

Loading…
Live editor
<StackLayout gap="sm">
  <SensorReading metric="temperature" value={22.4} unit="celsius" size="md" />
  <SensorReading
    metric="humidity"
    value={48}
    unit="percent-rh"
    fractionDigits={0}
    size="md"
  />
</StackLayout>

md​

Loading…
Live editor
<StackLayout gap="md">
  <SensorReading metric="temperature" value={22.4} unit="celsius" size="md" />
  <SensorReading
    metric="humidity"
    value={48}
    unit="percent-rh"
    fractionDigits={0}
    size="md"
  />
</StackLayout>

lg​

Loading…
Live editor
<StackLayout gap="lg">
  <SensorReading metric="temperature" value={22.4} unit="celsius" size="md" />
  <SensorReading
    metric="humidity"
    value={48}
    unit="percent-rh"
    fractionDigits={0}
    size="md"
  />
</StackLayout>

There's no gap above the first child or below the last one.

Nesting stacks​

Put a stack inside a stack to group things. Use a bigger gap outside and a smaller one inside, so the groups are easy to see:

Loading…
Live editor
<StackLayout gap="lg">
  <StackLayout gap="sm">
    <LocationPath spaceName="Bedroom" />
    <ModuleCard
      name="Climate Module"
      connectionStatus="connected"
      sensors={[{ metric: "temperature", value: 21.5, unit: "celsius" }]}
    />
  </StackLayout>
  <StackLayout gap="sm">
    <LocationPath spaceName="Kitchen" />
    <ModuleCard
      name="Light Module"
      connectionStatus="stale"
      sensors={[
        { metric: "illuminance", value: 320, unit: "lux", fractionDigits: 0 },
      ]}
    />
  </StackLayout>
</StackLayout>

Width​

StackLayout fills the width of its parent, and so does every child. A long child can't push the stack wider than its parent.

Most of the kit's components are meant to fill the width they get, so this is usually what you want. To keep a child at its own width, like a Button, wrap it in a <div>:

Loading…
Live editor
<StackLayout gap="sm">
  {/* Fills the stack */}
  <Button onClick={() => {}}>Full width</Button>
  {/* Keeps its own width */}
  <div>
    <Button onClick={() => {}}>Own width</Button>
  </div>
</StackLayout>

Props​

PropTypeDefaultDescription
childrenReactNode–Required. The components to place in one column, top to bottom.
gap"sm" | "md" | "lg""md"The space between the children: 8px, 16px or 32px.

The types StackLayoutProps and StackLayoutGap are exported too:

import type { StackLayoutProps, StackLayoutGap } from "@detriz-sh-kit/ui";

Long text​

StackLayout has no text of its own. Long content in a child stays inside the stack: each child handles its own long text (see its page). Here a long LocationPath is shortened with … instead of pushing the stack wider:

Loading…
Live editor
<div
  style={{ maxWidth: 240, outline: "1px dashed var(--shk-palette-gray-300)" }}
>
  <StackLayout gap="sm">
    <LocationPath
      siteName="Grandparents' summer house by the lake"
      spaceName="Kitchen and dining area on the ground floor"
    />
    <ModuleCard
      name="Climate Module"
      connectionStatus="connected"
      sensors={[{ metric: "temperature", value: 22.4, unit: "celsius" }]}
    />
  </StackLayout>
</div>

Accessibility​

What you get without doing anything:

  • StackLayout is a plain <div> with no role, because a stack has no meaning of its own. Screen readers go straight to its children.
  • The reading order is the order of the children, so what people hear matches what they see.

What's up to you:

  • Order. Put the children in the order people should read them. Don't reorder them with CSS.
  • Meaning. If the children are a list or a group with a name, StackLayout won't say so. Use a component that does, like ContentSection for a group with a heading.

Styling​

WhatToken
Gap between childrensm --shk-space-2 (8px), md --shk-space-4 (16px), lg --shk-space-8 (32px)

StackLayout has nothing else to style. The space tokens are shared by the whole kit, so changing one changes spacing everywhere.