Vitral 0.2
Layout

StackPanel

Arranges its children in one line, stacked or side by side, with even spacing between them.

Import

main.ts
import { StackPanel } from '@vitral/vue';

Vertical

The default. Children stack top to bottom and stretch to the panel's width; the gap is the stackpanel.spacing token.

Header
Body
Footer
<script setup lang="ts">import { StackPanel } from '@vitral/vue';</script> <template>    <StackPanel class="frame narrow">        <div class="box c1">Header</div>        <div class="box c2">Body</div>        <div class="box c3">Footer</div>    </StackPanel></template> <style scoped>.frame {    width: 100%;    padding: 0.5rem;    border: 1px dashed color-mix(in srgb, var(--vt-text-color) 30%, transparent);    border-radius: var(--vt-border-radius-md);} .narrow {    max-width: 18rem;} .box {    --c: var(--vt-chart-1);    padding: 0.5rem 0.75rem;    font-size: 0.8125rem;    color: var(--vt-text-color);    background: color-mix(in srgb, var(--c) 18%, transparent);    border: 1px solid color-mix(in srgb, var(--c) 55%, transparent);    border-radius: var(--vt-border-radius-sm);} .c1 {    --c: var(--vt-chart-1);} .c2 {    --c: var(--vt-chart-2);} .c3 {    --c: var(--vt-chart-3);}</style>

Orientation, spacing and alignment

The dashed frame is the panel. Align moves children across the line; justify spreads them along it.

One
Two
Three
<script setup lang="ts">import { Label, Select, StackPanel } from '@vitral/vue';import { computed, ref } from 'vue'; const orientation = ref<'vertical' | 'horizontal'>('horizontal');const align = ref('stretch');const justify = ref('start');// 'token' leaves `spacing` unset, so the panel falls back to the stackpanel.spacing token.const spacingChoice = ref('token');const spacing = computed(() => (spacingChoice.value === 'token' ? undefined : Number(spacingChoice.value))); const orientations = [    { label: 'Horizontal', value: 'horizontal' },    { label: 'Vertical', value: 'vertical' }];const aligns = ['stretch', 'start', 'center', 'end'].map((value) => ({ label: value, value }));const justifies = ['start', 'center', 'end', 'space-between', 'space-evenly'].map((value) => ({ label: value, value }));const spacings = [    { label: 'Token (0.5rem)', value: 'token' },    { label: '0', value: '0' },    { label: '4px', value: '4' },    { label: '16px', value: '16' },    { label: '32px', value: '32' }];</script> <template>    <div class="controls">        <StackPanel spacing="0.375rem" style="min-width: 16rem">            <Label for="sp-orientation">Orientation</Label>            <Select id="sp-orientation" v-model="orientation" :options="orientations" option-label="label" option-value="value" size="small" />        </StackPanel>        <StackPanel spacing="0.375rem" style="min-width: 16rem">            <Label for="sp-spacing">Spacing</Label>            <Select id="sp-spacing" v-model="spacingChoice" :options="spacings" option-label="label" option-value="value" size="small" />        </StackPanel>        <StackPanel spacing="0.375rem" style="min-width: 16rem">            <Label for="sp-align">Align</Label>            <Select id="sp-align" v-model="align" :options="aligns" option-label="label" option-value="value" size="small" />        </StackPanel>        <StackPanel spacing="0.375rem" style="min-width: 16rem">            <Label for="sp-justify">Justify</Label>            <Select id="sp-justify" v-model="justify" :options="justifies" option-label="label" option-value="value" size="small" />        </StackPanel>    </div>    <StackPanel class="frame tall" :orientation="orientation" :spacing="spacing" :align="align" :justify="justify">        <div class="box c1 s1">One</div>        <div class="box c2 s2">Two</div>        <div class="box c3 s3">Three</div>    </StackPanel></template> <style scoped>.controls {    display: flex;    flex-wrap: wrap;    gap: 0.75rem;    width: 100%;} .controls .demo-field {    min-width: 10rem;} .frame {    width: 100%;    padding: 0.5rem;    border: 1px dashed color-mix(in srgb, var(--vt-text-color) 30%, transparent);    border-radius: var(--vt-border-radius-md);} .tall {    min-height: 11rem;} .box {    --c: var(--vt-chart-1);    padding: 0.5rem 0.75rem;    font-size: 0.8125rem;    color: var(--vt-text-color);    background: color-mix(in srgb, var(--c) 18%, transparent);    border: 1px solid color-mix(in srgb, var(--c) 55%, transparent);    border-radius: var(--vt-border-radius-sm);} .c1 {    --c: var(--vt-chart-1);} .c2 {    --c: var(--vt-chart-2);} .c3 {    --c: var(--vt-chart-3);} .s1 {    min-width: 4rem;    min-height: 2rem;} .s2 {    min-width: 6rem;    min-height: 3.5rem;} .s3 {    min-width: 8rem;    min-height: 5rem;}</style>

Wrap

A horizontal stack with wrap flows onto more lines instead of overflowing.

VueReactAngularSveltePresetsTokensPass-throughUnstyledFlexboxAccessibilityLayoutPanels
<script setup lang="ts">import { StackPanel } from '@vitral/vue'; const tags = ['Vue', 'React', 'Angular', 'Svelte', 'Presets', 'Tokens', 'Pass-through', 'Unstyled', 'Flexbox', 'Accessibility', 'Layout', 'Panels'];</script> <template>    <StackPanel class="frame" orientation="horizontal" wrap :spacing="6">        <span v-for="(tag, i) in tags" :key="tag" class="box" :class="`c${(i % 5) + 1}`">{{ tag }}</span>    </StackPanel></template> <style scoped>.frame {    width: 100%;    padding: 0.5rem;    border: 1px dashed color-mix(in srgb, var(--vt-text-color) 30%, transparent);    border-radius: var(--vt-border-radius-md);} .box {    --c: var(--vt-chart-1);    padding: 0.5rem 0.75rem;    font-size: 0.8125rem;    color: var(--vt-text-color);    background: color-mix(in srgb, var(--c) 18%, transparent);    border: 1px solid color-mix(in srgb, var(--c) 55%, transparent);    border-radius: var(--vt-border-radius-sm);} .c1 {    --c: var(--vt-chart-1);} .c2 {    --c: var(--vt-chart-2);} .c3 {    --c: var(--vt-chart-3);} .c4 {    --c: var(--vt-chart-4);} .c5 {    --c: var(--vt-chart-5);}</style>

API

Read from packages/vue/src/components/StackPanel/types.ts, so it says what the component actually accepts.

Props

NameTypeDescription
orientation'vertical' | 'horizontal'Children one below the other (the default) or side by side.
spacingnumber | stringSpace between children: a number of pixels or any CSS length. Defaults to the `stackpanel.spacing` token.
alignstringCross-axis alignment (`align-items`): `start`, `center`, `end`, `baseline`, or `stretch`, the default.
justifystringMain-axis distribution (`justify-content`): `start`, `center`, `end`, `space-between`…
wrapbooleanLet children flow onto another line when they run out of room.
asstring | ComponentThe element or component to render: `'ul'` for a list, `'nav'`, `'form'`.

Plus pt, dt and unstyled from BaseProps, see pass-through and unstyled mode.

Slots

NameSlot propsDescription
default——