Skip to content

Drawer ​

Shows content that needs more room than a dialog, in a full-height panel beside the page: a record to read or edit, a list's filters.

vue
<script setup lang="ts">
import { FsButton, FsDrawer, FsField, FsInput } from '@fivespark/ui'
import { ref } from 'vue'

const name = ref('Jansen Bouw B.V.')
const city = ref('Utrecht')
</script>

<template>
  <div class="grid min-h-[28rem] place-items-center">
    <FsDrawer title="Klant bewerken">
      <template #trigger="{ props }">
        <FsButton v-bind="props" label="Klant bewerken" />
      </template>
      <div class="flex flex-col gap-4">
        <FsField label="Bedrijfsnaam"><FsInput v-model="name" autofocus /></FsField>
        <FsField label="Plaats"><FsInput v-model="city" /></FsField>
      </div>
      <template #footer="{ close }">
        <FsButton label="Annuleren" @click="close" />
        <FsButton variant="primary" label="Opslaan" @click="close" />
      </template>
    </FsDrawer>
  </div>
</template>

Usage ​

vue
<script setup lang="ts">
import { FsButton, FsDrawer } from '@fivespark/ui'
</script>

<template>
  <FsDrawer title="Filters">
    <template #trigger="{ props }">
      <FsButton v-bind="props" label="Filters" />
    </template>
    …
  </FsDrawer>
</template>

The drawer sits at the end of the page and closes only by Esc, its close button or its own buttons. For a question to answer or a short task, use a Dialog.

Examples ​

Filters ​

"Toepassen" applies and closes; "Wissen" clears and leaves the drawer open. Closing any other way should discard what was changed, which your page does by resetting the fields.

vue
<script setup lang="ts">
import { FsButton, FsDrawer, FsField, FsInput } from '@fivespark/ui'
import { ref, watch } from 'vue'

const open = ref(false)
const klant = ref('')
const toegepast = ref('')

watch(open, (isOpen) => {
  if (!isOpen) klant.value = toegepast.value
})
</script>

<template>
  <div class="grid min-h-[28rem] place-items-center">
    <FsDrawer v-model:open="open" title="Filters">
      <template #trigger="{ props }">
        <FsButton v-bind="props" label="Filters" leading-icon="funnel" />
      </template>
      <FsField label="Klant"><FsInput v-model="klant" autofocus /></FsField>
      <template #footer="{ close }">
        <FsButton variant="ghost" label="Wissen" @click="klant = ''" />
        <FsButton variant="primary" label="Toepassen" @click="toegepast = klant; close()" />
      </template>
    </FsDrawer>
  </div>
</template>

A record to read ​

Without a form, leave out autofocus and the footer. Focus starts on the close button.

vue
<script setup lang="ts">
import { FsButton, FsDescriptionList, FsDrawer } from '@fivespark/ui'

const items = [
  { label: 'Klant', content: 'Jansen Bouw B.V.' },
  { label: 'Totaal', content: '€ 4.180,00' },
  { label: 'Leverdatum', content: '12 december 2026' },
]
</script>

<template>
  <div class="grid min-h-[28rem] place-items-center">
    <FsDrawer title="Order 2026-0318" description="Geplaatst op 4 november 2026.">
      <template #trigger="{ props }">
        <FsButton v-bind="props" label="Order bekijken" />
      </template>
      <FsDescriptionList :items />
    </FsDrawer>
  </div>
</template>

Controlled with v-model ​

Without a trigger, open it from anywhere with v-model:open.

vue
<script setup lang="ts">
import { FsButton, FsDrawer } from '@fivespark/ui'
import { ref } from 'vue'

const open = ref(false)
</script>

<template>
  <div class="grid min-h-[28rem] place-items-center">
    <FsButton label="Hulp bij plannen" @click="open = true" />
    <FsDrawer v-model:open="open" title="Hulp bij plannen" description="Kies een order en een dag, en wijs er een monteur aan toe.">
      <template #footer="{ close }">
        <FsButton label="Sluiten" @click="close" />
      </template>
    </FsDrawer>
  </div>
</template>

A confirmation inside a drawer is a Dialog with alert, opened from the drawer. Place the drawer outside any <form>.

Keyboard ​

KeyDoes
EscCloses the drawer. A popover or select open inside it takes the key first
Tab, Shift + TabMoves between the controls inside; focus stays in the drawer
Enter, SpaceOn the trigger, opens the drawer; on the close button, closes it

API Reference ​

FsDrawer ​

PropTypeDefaultDescription
titlestringrequiredShown at the top as a heading, and names the drawer.
descriptionstringA sentence at the top of the body, read out with the name.
openbooleanfalseTrue while the drawer shows, however it was opened. Set it to open or close the drawer.
EventPayloadDescription
update:open[value: boolean]Sent with the new `open`, for `v-model:open`.
SlotPropsDescription
trigger{ props: Record<string, unknown>; }The button that opens it: bind `props` on it, `<FsButton v-bind="props" label="Filters" />`. Focus returns to it on close.
default{ close: () => void; }The body, below the description. `close()` closes the drawer.
footer{ close: () => void; }The actions, at the bottom. `close()` closes the drawer, for a Cancel button.