Skip to content
ts
import Layout from '~/ui/Layout.vue'

Layout ​

CSS provides four methods to arrange items in a container: Flow, Columns, Flex and Grid. To make typical alignment tasks in the Funkwhale UI easier, we have created a few useful presets.

By default, the items have a 32px gap. You can change it with the gap-x prop.

Apply presets ​

The following containers are responsive. Change your window's size or select a device preset from your browser's dev tools to see how layouts are affected by available space.

Example removed. Layout is deprecated. Use <div class=layout-row and friends.

Add semantics ​

Add one of these props to your Layout component to turn them into semantic containers (without affecting their presentation):

Headings: "h1" | "h2" | "h3" | "h4" | "h5"

Sectioning: "nav" | "aside" | "header" | "footer" | "main"

Forms: "label" | "form"

Common props ​

gap-*: Set the gap to one of the defaults ​

ts
`gap-${'4' | '8' | '12' | '16' | '24' | '32' | '48' | '64' | 'auto'}`

no-gap: Remove the gap between items ​

vue
<script setup>
const noGap = ref(true);
</script>

<template>
  <Switch v-model="noGap" label="no-gap" />

  <Layout flex :no-gap="noGap || undefined">
    <Card title="A" small />
    <Card title="B" small />
    <Card title="C" small />
    <Card title="D" small />
  </Layout>
</template>

A

B

C

D

Add fixed or flexible Spacers ​

Only available on:

  • stack
  • flex

If you add a spacer with attribute grow, it will push the other item until the Layout fills the available space. This only works if the parent element itself grows beyond its minimal contents.

vue
<script setup>
const isGrowing = ref(true);
</script>

<template>
  <Switch v-model="isGrowing" label="Grow spacers" />

  <Layout stack style="height:25em;">
    <Alert red />
    <Alert purple />
    <Spacer :grow="isGrowing || undefined" />
    <Alert blue />
  </Layout>
</template>

Multiple spacers will distribute their growth evenly.

Note that you can set the minimum space occupied by the Spacer with its size prop (docs). Negative values can offset the gap of the Layout (but, due to a limitation of flexbox, not eat into the space occupied by adjacent items):

vue
<template>
  <Switch v-model="isGrowing" label="Grow spacers" />

  <Layout stack style="height:35em;">
    <Alert blue />
    <Spacer :size="-32" :grow="isGrowing || undefined" />
    <Alert green />
    <Alert yellow />
    <Spacer :size="-32" :grow="isGrowing || undefined" />
    <Alert red />
  </Layout>
</template>

Using this component

A11y Checklist ​

Accessible layout ​

template
<Layout flex>
  <Button>1</Button>
  <Button>2</Button>
  <Button>3</Button>
  <Button>4</Button>
  <Button>5</Button>
</Layout>
<Layout grid>
  <Button>1</Button>
  <Button>2</Button>
  <Button>3</Button>
  <Button>4</Button>
  <Button>5</Button>
</Layout>
<Layout
  columns
  column-width="200"
>
  <Button>1</Button>
  <Button>2</Button>
  <Button>3</Button>
  <Button>4</Button>
  <Button>5</Button>
  <Button>6</Button>
</Layout>

Test this component in isolation against WCAG2 criteria