Component
Toolbar
<DomToolbar>A compact action surface for icon buttons, segmented controls, filters, and overflow menus.
Playground
Try every prop live
Toolbar playground
Use DomToolbar to group icon buttons, dropdowns, toggles, filters, and overflow menus.
Playground.vuevue
<script setup>
import { reactive } from 'vue';
import { DomToolbar } from '@getdom/studio/vue';
const data = reactive({
"as": "div",
"label": "Toolbar",
"orientation": "horizontal",
"align": "start",
"wrap": true,
"inset": false
});
</script>
<template>
<DomToolbar
v-bind="data"
/>
</template>Demo
Editor toolbar
Pair DomToolbar with DomIconButton, DomTooltip, and DomDropdown for compact app chrome.
Active tool:
select Zoom: 100%<script setup>
import { ref } from 'vue';
import { DomDropdown, DomIconButton, DomToolbar, DomTooltip } from '@getdom/studio/vue';
const activeTool = ref('select');
const zoom = ref('100%');
const icons = {
select: 'M5 4l10 8-4 1.5L9 20 5 4Z',
comment: 'M5 6h14v9H9l-4 4V6Z',
frame: 'M5 5h14v14H5V5Zm4 0v14M15 5v14M5 9h14M5 15h14',
undo: 'M9 7H5v4M5 11a7 7 0 1 0 2-5',
redo: 'M15 7h4v4M19 11a7 7 0 1 1-2-5',
};
const zoomItems = [
{ label: '50%', value: '50%' },
{ label: '75%', value: '75%' },
{ label: '100%', value: '100%' },
{ label: '150%', value: '150%' },
{ label: 'Fit to screen', value: 'Fit' },
];
</script>
<template>
<div class="flex w-full max-w-2xl flex-col gap-4">
<DomToolbar label="Canvas tools" class="w-fit">
<DomTooltip text="Select">
<DomIconButton label="Select" :active="activeTool === 'select'" @click="activeTool = 'select'">
<svg viewBox="0 0 24 24" class="size-4" fill="none" aria-hidden="true">
<path :d="icons.select" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</DomIconButton>
</DomTooltip>
<DomTooltip text="Frame">
<DomIconButton label="Frame" :active="activeTool === 'frame'" @click="activeTool = 'frame'">
<svg viewBox="0 0 24 24" class="size-4" fill="none" aria-hidden="true">
<path :d="icons.frame" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</DomIconButton>
</DomTooltip>
<DomTooltip text="Comment">
<DomIconButton label="Comment" :active="activeTool === 'comment'" @click="activeTool = 'comment'">
<svg viewBox="0 0 24 24" class="size-4" fill="none" aria-hidden="true">
<path :d="icons.comment" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</DomIconButton>
</DomTooltip>
<span class="mx-1 h-6 w-px bg-border" aria-hidden="true"></span>
<DomTooltip text="Undo">
<DomIconButton label="Undo">
<svg viewBox="0 0 24 24" class="size-4" fill="none" aria-hidden="true">
<path :d="icons.undo" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</DomIconButton>
</DomTooltip>
<DomTooltip text="Redo">
<DomIconButton label="Redo">
<svg viewBox="0 0 24 24" class="size-4" fill="none" aria-hidden="true">
<path :d="icons.redo" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</DomIconButton>
</DomTooltip>
<span class="mx-1 h-6 w-px bg-border" aria-hidden="true"></span>
<DomDropdown :items="zoomItems" :label="zoom" width="min-w-[9rem]" @select="(value) => zoom = value" />
</DomToolbar>
<div class="rounded-2xl border border-border bg-secondary/30 p-4 text-sm text-muted-fg">
Active tool: <code class="text-fg">{{ activeTool }}</code>
<span aria-hidden="true"> / </span>
Zoom: <code class="text-fg">{{ zoom }}</code>
</div>
</div>
</template>
Demo
Inset composer toolbar
Place a compact formatting toolbar inside the lower edge of a composer or textarea shell.
<script setup>
import { reactive, ref } from 'vue';
import { DomIconButton, DomToolbar, DomTooltip } from '@getdom/studio/vue';
const message = ref('Hi team,\n\nI moved the launch notes into the shared doc and flagged the open approvals.');
const active = reactive({
bold: false,
link: true,
list: false,
});
const icons = {
link: 'M10 13a5 5 0 0 0 7 0l2-2a5 5 0 0 0-7-7l-1 1M14 11a5 5 0 0 0-7 0l-2 2a5 5 0 0 0 7 7l1-1',
list: 'M8 6h11M8 12h11M8 18h11M4 6h.01M4 12h.01M4 18h.01',
attach: 'M21 12.5 12 21a6 6 0 0 1-8.5-8.5L13 3a4 4 0 1 1 5.5 5.5L9 18a2 2 0 0 1-3-3l9-9',
};
function toggle(key) {
active[key] = !active[key];
}
</script>
<template>
<div class="w-full max-w-2xl rounded-2xl border border-border bg-background shadow-sm">
<textarea
v-model="message"
class="min-h-40 w-full resize-none bg-transparent px-4 pt-4 text-sm leading-6 text-fg outline-none placeholder:text-muted-fg"
placeholder="Write a message..."
></textarea>
<div class="px-2 pb-2">
<DomToolbar label="Message formatting" inset align="between" class="w-full">
<span class="flex min-w-0 items-center gap-1">
<DomTooltip text="Bold">
<DomIconButton label="Bold" size="sm" :active="active.bold" @click="toggle('bold')">
<span class="text-sm font-bold leading-none">B</span>
</DomIconButton>
</DomTooltip>
<DomTooltip text="Add link">
<DomIconButton label="Add link" size="sm" :active="active.link" @click="toggle('link')">
<svg viewBox="0 0 24 24" class="size-4" fill="none" aria-hidden="true">
<path :d="icons.link" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</DomIconButton>
</DomTooltip>
<DomTooltip text="Bulleted list">
<DomIconButton label="Bulleted list" size="sm" :active="active.list" @click="toggle('list')">
<svg viewBox="0 0 24 24" class="size-4" fill="none" aria-hidden="true">
<path :d="icons.list" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</DomIconButton>
</DomTooltip>
<span class="mx-1 h-5 w-px bg-border" aria-hidden="true"></span>
<DomTooltip text="Attach file">
<DomIconButton label="Attach file" size="sm">
<svg viewBox="0 0 24 24" class="size-4" fill="none" aria-hidden="true">
<path :d="icons.attach" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</DomIconButton>
</DomTooltip>
</span>
<span class="flex items-center gap-2">
<span class="hidden text-xs text-muted-fg sm:inline">{{ message.length }} chars</span>
<button type="button" class="rounded-full bg-primary px-3 py-1.5 text-xs font-semibold text-primary-fg transition hover:opacity-90">
Send
</button>
</span>
</DomToolbar>
</div>
</div>
</template>
Demo
Formatting toolbar
Show classic WYSIWYG formatting controls with active button states.
Paragraph
Quarterly launch summary
Active: bold, underline, list
<script setup>
import { computed, reactive, ref } from 'vue';
import { DomDropdown, DomIconButton, DomToolbar, DomTooltip } from '@getdom/studio/vue';
const block = ref('Paragraph');
const active = reactive({
bold: true,
italic: false,
underline: true,
strike: false,
quote: false,
list: true,
});
const blockItems = [
{ label: 'Paragraph', value: 'Paragraph' },
{ label: 'Heading 2', value: 'Heading 2' },
{ label: 'Callout', value: 'Callout' },
];
const icons = {
quote: 'M9 7H5v6h4V7Zm10 0h-4v6h4V7Z',
list: 'M8 6h11M8 12h11M8 18h11M4 6h.01M4 12h.01M4 18h.01',
link: 'M10 13a5 5 0 0 0 7 0l2-2a5 5 0 0 0-7-7l-1 1M14 11a5 5 0 0 0-7 0l-2 2a5 5 0 0 0 7 7l1-1',
};
const activeMarks = computed(() => {
return Object.entries(active)
.filter(([, value]) => value)
.map(([key]) => key)
.join(', ') || 'plain';
});
function toggle(key) {
active[key] = !active[key];
}
</script>
<template>
<div class="flex w-full max-w-2xl flex-col gap-3">
<DomToolbar label="Text formatting" class="w-fit">
<DomDropdown :items="blockItems" :label="block" width="min-w-[10rem]" @select="(value) => block = value" />
<span class="mx-1 h-6 w-px bg-border" aria-hidden="true"></span>
<DomTooltip text="Bold">
<DomIconButton label="Bold" size="sm" :active="active.bold" @click="toggle('bold')">
<span class="text-sm font-bold leading-none">B</span>
</DomIconButton>
</DomTooltip>
<DomTooltip text="Italic">
<DomIconButton label="Italic" size="sm" :active="active.italic" @click="toggle('italic')">
<span class="font-serif text-sm italic leading-none">I</span>
</DomIconButton>
</DomTooltip>
<DomTooltip text="Underline">
<DomIconButton label="Underline" size="sm" :active="active.underline" @click="toggle('underline')">
<span class="text-sm font-semibold leading-none underline underline-offset-2">U</span>
</DomIconButton>
</DomTooltip>
<DomTooltip text="Strikethrough">
<DomIconButton label="Strikethrough" size="sm" :active="active.strike" @click="toggle('strike')">
<span class="text-sm font-semibold leading-none line-through">S</span>
</DomIconButton>
</DomTooltip>
<span class="mx-1 h-6 w-px bg-border" aria-hidden="true"></span>
<DomTooltip text="Quote">
<DomIconButton label="Quote" size="sm" :active="active.quote" @click="toggle('quote')">
<svg viewBox="0 0 24 24" class="size-4" fill="none" aria-hidden="true">
<path :d="icons.quote" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</DomIconButton>
</DomTooltip>
<DomTooltip text="Bulleted list">
<DomIconButton label="Bulleted list" size="sm" :active="active.list" @click="toggle('list')">
<svg viewBox="0 0 24 24" class="size-4" fill="none" aria-hidden="true">
<path :d="icons.list" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</DomIconButton>
</DomTooltip>
<DomTooltip text="Insert link">
<DomIconButton label="Insert link" size="sm">
<svg viewBox="0 0 24 24" class="size-4" fill="none" aria-hidden="true">
<path :d="icons.link" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</DomIconButton>
</DomTooltip>
</DomToolbar>
<div class="rounded-2xl border border-border bg-background p-4 text-sm shadow-sm">
<p class="mb-2 text-xs font-medium uppercase text-muted-fg">{{ block }}</p>
<p
class="text-base leading-7 text-fg"
:class="{
'font-bold': active.bold,
'italic': active.italic,
'underline underline-offset-4': active.underline,
'line-through': active.strike,
}"
>
Quarterly launch summary
</p>
<p class="mt-3 text-xs text-muted-fg">Active: {{ activeMarks }}</p>
</div>
</div>
</template>
Reference
Props
Control props
| Name | Type | TS | Default | Description |
|---|---|---|---|---|
as | string | string | 'div' | Element to render. |
label | string | string | 'Toolbar' | Accessible toolbar label. |
orientation | 'horizontal' | 'vertical' | string | 'horizontal' | Toolbar direction. |
align | 'start' | 'center' | 'end' | 'between' | string | 'start' | Control alignment. |
wrap | boolean | boolean | true | Allow controls to wrap on narrow screens. |
inset | boolean | boolean | false | Use inset skin instead of control skin. |
Auto-generated from Toolbar.props and inline _edit hints.
Slots
| Name | Scope | Description |
|---|---|---|
| #(default) | — | Toolbar controls. |