Keyboard shortcut: Ctrl + K
Get started

Empty state

VEmptyState says that there is nothing to show yet, and offers what to do about it.

Usage

vue

No invoices yet

Invoices you create or import appear here.
<script setup lang="ts">
import { VButton, VEmptyState } from 'vectis-ui'
import { description } from 'vectis-ui/icons'
</script>

<template>
  <VEmptyState
    :icon="description"
    title="No invoices yet"
    description="Invoices you create or import appear here."
  >
    <template #actions>
      <VButton>Create an invoice</VButton>
      <VButton variant="outline" tone="neutral">Import</VButton>
    </template>
  </VEmptyState>
</template>

Examples

Sizes

size scales the badge, the spacing and the title: sm for a panel or a list, lg for a whole page.

vue

Nothing in this folder

The scale follows the space it fills.

No messages

The scale follows the space it fills.

Your workspace is empty

The scale follows the space it fills.
<script setup lang="ts">
import { VEmptyState } from 'vectis-ui'
import type { EmptyStateSize } from 'vectis-ui'
import { inbox } from 'vectis-ui/icons'

const SIZES: { size: EmptyStateSize; title: string }[] = [
  { size: 'sm', title: 'Nothing in this folder' },
  { size: 'md', title: 'No messages' },
  { size: 'lg', title: 'Your workspace is empty' },
]
</script>

<template>
  <div class="stack">
    <VEmptyState
      v-for="item in SIZES"
      :key="item.size"
      class="frame"
      :size="item.size"
      :icon="inbox"
      :title="item.title"
      description="The scale follows the space it fills."
    />
  </div>
</template>

<style scoped>
.stack {
  display: grid;
  gap: var(--vectis-space-4);
}

.frame {
  border: 1px dashed var(--vectis-color-border);
  border-radius: var(--vectis-radius-surface);
}
</style>

Content and heading level

The default slot replaces description with text that holds links. headingLevel renders the title as a heading without changing how it looks.

vue

You are all caught up

New mentions and replies show up here. Choose what you hear about in your notification settings.
<script setup lang="ts">
import { VEmptyState } from 'vectis-ui'
import { notifications } from 'vectis-ui/icons'
</script>

<template>
  <VEmptyState :icon="notifications" title="You are all caught up" :heading-level="2">
    New mentions and replies show up here. Choose what you hear about in your
    <a href="#content">notification settings</a>.
  </VEmptyState>
</template>

In tables and comboboxes

VDataTable and VCombobox show a small empty state titled with their emptyText. Their empty slot replaces it, for instance with an empty state that has actions.

vue
NameStatus

No orders

NameStatus

No orders yet

Orders placed by your customers appear here.
<script setup lang="ts">
import { ref } from 'vue'
import { VButton, VCombobox, VDataTable, VEmptyState } from 'vectis-ui'
import { inbox } from 'vectis-ui/icons'

const COLUMNS = [
  { key: 'name', label: 'Name' },
  { key: 'status', label: 'Status' },
]

const OPTIONS = [
  { value: 'fr', label: 'France' },
  { value: 'de', label: 'Germany' },
]

const country = ref('')
</script>

<template>
  <div class="stack">
    <VDataTable :columns="COLUMNS" :rows="[]" empty-text="No orders" />

    <VDataTable :columns="COLUMNS" :rows="[]">
      <template #empty>
        <VEmptyState
          size="sm"
          :icon="inbox"
          title="No orders yet"
          description="Orders placed by your customers appear here."
        >
          <template #actions>
            <VButton size="sm">Create an order</VButton>
          </template>
        </VEmptyState>
      </template>
    </VDataTable>

    <VCombobox
      v-model="country"
      class="combobox"
      :options="OPTIONS"
      label="Country"
      empty-text="No country found"
    />
  </div>
</template>

<style scoped>
.stack {
  display: grid;
  gap: var(--vectis-space-6);
}

.combobox {
  max-inline-size: 18rem;
}
</style>

API

Props

PropTypeDefault
titlestringnone
What is empty, in a few words.
descriptionstringnone
Why, or what to do next. Replaced by the default slot.
iconIconSourcenone
Icon drawn in a round badge. Replaced by the media slot.
sizeEmptyStateSize'sm' | 'md' | 'lg''md'
Scale of the block.
headingLevelEmptyStateHeadingLevel1 | 2 | 3 | 4 | 5 | 6none
Renders the title as h1 to h6. Without it, the title is a paragraph.

Slots

SlotType
default{}
Description with formatting or links.
media{}
Illustration replacing the icon badge.
actions{}
Buttons or links that leave the empty state.

Types

Types used in the API tables. Import exported types from vectis-ui.

export interface BuiltinIcon {
  name: string
  paths: readonly [string] | readonly [string, string]
}
export type IconRender =
  | { path: string; viewBox?: string }
  | { component: Component; props?: Record<string, unknown> }
  | { src: string }
  | { text: string; class?: string }
  | { class: string }
export type IconSource = string | BuiltinIcon | IconRender

CSS variables

TokenValue
--vectis-control-size-empty-state-media-sm2.5rem
--vectis-control-size-empty-state-media-md3rem
--vectis-control-size-empty-state-media-lg4rem
--vectis-control-size-empty-state-text-max28rem