Dock
The macOS dock, in Material.
Walkthrough
1. Basic
Move the pointer along the bar: the tile under it swells, its neighbours less, and the name rises over it. On a touch screen the tiles stay put at a finger's size; from the keyboard the arrow keys walk them.
<script lang="ts"> import { Dock, DockItem, DockDivider } from 'omaris'; import Icon from '$lib/patterns/shell/icon.svelte'; const APPS = [ { name: 'Home', icon: 'home' }, { name: 'Mail', icon: 'mail', badge: 3 }, { name: 'Calendar', icon: 'calendar' }, { name: 'Messages', icon: 'message' }, { name: 'Music', icon: 'music' }, { name: 'Settings', icon: 'settings' } ] as const; let current = $state('Home');</script><div class="flex w-full flex-1 items-end justify-center"> <Dock label="Apps"> {#each APPS as app (app.name)} <DockItem label={app.name} active={current === app.name} badge={'badge' in app ? app.badge : undefined} onclick={() => (current = app.name)} > <Icon name={app.icon} /> </DockItem> {/each} <DockDivider /> <DockItem label="Trash"><Icon name="trash" /></DockItem> </Dock></div> 2. Vertical
Down the side, the way a rail sits. Labels ride out beside the tiles.
<script lang="ts"> import { Dock, DockItem } from 'omaris'; import Icon from '$lib/patterns/shell/icon.svelte'; const TOOLS = [ { name: 'Select', icon: 'target' }, { name: 'Draw', icon: 'edit' }, { name: 'Crop', icon: 'crop' }, { name: 'Adjust', icon: 'sliders' }, { name: 'Magic', icon: 'wand' } ] as const; let tool = $state('Select');</script><div class="flex w-full flex-1 items-center"> <Dock orientation="vertical" label="Tools" variant="filled"> {#each TOOLS as item (item.name)} <DockItem label={item.name} active={tool === item.name} onclick={() => (tool = item.name)}> <Icon name={item.icon} /> </DockItem> {/each} </Dock></div> 3. Glass
variant="glass" sets the tiles on frosted glass: what is behind the bar blurs through it.
<script lang="ts"> import { Dock, DockItem } from 'omaris'; import Icon from '$lib/patterns/shell/icon.svelte'; const APPS = [ { name: 'Home', icon: 'home' }, { name: 'Photos', icon: 'image' }, { name: 'Camera', icon: 'camera' }, { name: 'Maps', icon: 'navigation' }, { name: 'Music', icon: 'music' }, { name: 'Settings', icon: 'settings' } ] as const;</script><div class="relative flex min-h-72 w-full items-end justify-center overflow-hidden rounded-shape-xl bg-linear-to-br from-primary via-tertiary to-warning p-6"> <div class="absolute inset-x-8 top-8 grid grid-cols-3 gap-3"> {#each Array.from({ length: 6 }, (_, i) => i) as cell (cell)} <div class="h-12 rounded-shape-md bg-background/35"></div> {/each} </div> <Dock variant="glass" label="Apps"> {#each APPS as app (app.name)} <DockItem label={app.name} active={app.name === 'Home'}> <Icon name={app.icon} /> </DockItem> {/each} </Dock></div> 4. Labels and links
labels="always" prints the names under the tiles, href makes a tile a link, and magnification={1} keeps the bar still for a toolbar that is pressed more than admired.
<script lang="ts"> import { Dock, DockItem } from 'omaris'; import Icon from '$lib/patterns/shell/icon.svelte';</script><div class="flex w-full flex-1 items-end justify-center"> <Dock labels="always" magnification={1} variant="filled" label="Shortcuts"> <DockItem label="Repo" href="https://github.com" target="_blank" ><Icon name="github" /></DockItem > <DockItem label="Docs" href="/docs/components/dock" active><Icon name="file" /></DockItem> <DockItem label="Blocks" href="/blocks" badge><Icon name="activity" /></DockItem> <DockItem label="Learn" href="/learn" badge={2}><Icon name="rocket" /></DockItem> </Dock></div> 5. Overridden
The overridden case: a bigger base tile, a square dark bar and tiles restyled through classes — the dock still owns their size, so only the look changes.
<script lang="ts"> import { Dock, DockItem } from 'omaris'; import Icon from '$lib/patterns/shell/icon.svelte'; const APPS = [ { name: 'Home', icon: 'home' }, { name: 'Search', icon: 'search' }, { name: 'Library', icon: 'layers' }, { name: 'Profile', icon: 'user' } ] as const;</script><div class="flex w-full flex-1 items-end justify-center"> <Dock size={56} magnification={1.5} distance={110} label="Apps" classes={{ surface: 'rounded-shape-lg bg-inverse-surface ring-0' }} > {#each APPS as app (app.name)} <DockItem label={app.name} active={app.name === 'Home'} classes={{ control: 'rounded-shape-md bg-inverse-surface text-inverse-surface-foreground ring-1 ring-inverse-surface-foreground/15 ring-inset', dot: 'bg-inverse-surface-foreground' }} > <Icon name={app.icon} /> </DockItem> {/each} </Dock></div>