Launch Dock

Mac-Style App Dock for React

A dock of app icons under a window. Pick one and its window grows up out of the icon in 0.3s, over the open one, which dissolves where it is. One label glides over the dock as you point, and with autoplay the dot under the open app fills like a timer before the next one launches.

  • Showcase
  • Testimonials
  • Motion

Uses motion, clsx, tailwind-merge

Inspired by ToDesktop

Open in ChatGPTOpen in Claude
frame
fadetrue
duration0.30s
hoverScale1.10×
<LaunchDock />

The demo follows as you drag.

Field notes: Lisbon offsite

Plume · Docs that research teams write together, offline on the train.

Take this demo to your coding agent.
Add this moment from KeyframeUI to our project and adapt it to our content.

Launch Dock: A dock of app icons under a window. Pick one and its window grows up out of the icon in 0.3s, over the open one, which dissolves where it is. One label glides over the dock as you point, and with autoplay the dot under the open app fills like a timer before the next one launches.
This demo, Customer Apps: Six apps built on one sync platform, each with its own window. Autoplay walks through them until you pick one, and the line under the dock follows the open app.

1. Install it:
   npx shadcn@latest add @keyframeui/launch-dock-demo
   (If the CLI can't find @keyframeui, use https://keyframeui.com/r/launch-dock-demo.json instead.)
   It adds the demo, components/launch-dock-demo.tsx, and the component, components/ui/launch-dock.tsx.

2. Make it ours: our copy, data, images and colors. Keep the structure the motion depends on. If we only need the effect, use <LaunchDock> on its own.

3. These props set its feel. Change them before you change the file:
   - frame (default "window"): What the content sits in: a desktop window with three lights and a centered title, a plain card, or nothing, for content that brings its own frame.
   - fade (default true): Fade the window's lower edge out behind the dock, the way the reference desktop sinks into the page. Turn it off to keep all of the content in view; the dock then sits under the window.
   - duration (default 0.3): Seconds a window takes to grow up out of its icon. The open one dissolves in step, so it's gone just before the new one lands.
   - hoverScale (default 1.1): The scale an icon grows to as it rises under the pointer. `1` keeps its size.

4. Don't change, in components/ui/launch-dock.tsx:
   - Windows animate only transform and opacity, as hardware animations on their own layers, and closing animates opacity alone; nothing repaints mid-flight.
   - The open window never moves: it dissolves in place under the new one (z-index 2 over 1), which is opaque from its first frame behind the icon, so two windows never cross or blend.
   - A pick measures its icon before any state changes, so the launch's first frame never waits on layout.
   - A launch turns round from wherever it is: a window still dissolving comes back in place instead of growing from its icon again.
   - Closed windows stay mounted, `hidden` and `inert`, as tabpanels of a tablist with a roving `tabIndex`, so their content and state survive a switch.
   Its timing is all in the TIMING block at the top of that file.

Docs: https://keyframeui.com/components/launch-dock.md

Installation

Add the component on its own with the CLI, or copy the file in by hand.

The CLI writes components/ui/launch-dock.tsx and installs motion, clsx and tailwind-merge. It needs the @keyframeui registry in components.json; add it once per project.

npx shadcn@latest add @keyframeui/launch-dock

Examples

Finished sections built with Launch Dock. Each one installs whole, with the component included.

Testimonials

Faces in a round dock. Each quote card grows out of the person who said it, and shrinks back into them when the next one opens.

Okto for teams

Teams that stopped taking notes
Take this demo to your coding agent.
Add this moment from KeyframeUI to our project and adapt it to our content.

Launch Dock: A dock of app icons under a window. Pick one and its window grows up out of the icon in 0.3s, over the open one, which dissolves where it is. One label glides over the dock as you point, and with autoplay the dot under the open app fills like a timer before the next one launches.
This demo, Testimonials: Faces in a round dock. Each quote card grows out of the person who said it, and shrinks back into them when the next one opens.

1. Install it:
   npx shadcn@latest add @keyframeui/launch-dock-quotes-demo
   (If the CLI can't find @keyframeui, use https://keyframeui.com/r/launch-dock-quotes-demo.json instead.)
   It adds the demo, components/launch-dock-quotes-demo.tsx, and the component, components/ui/launch-dock.tsx.

2. Make it ours: our copy, data, images and colors. Keep the structure the motion depends on. If we only need the effect, use <LaunchDock> on its own.

3. These props set its feel. Change them before you change the file:
   - frame (default "window"): What the content sits in: a desktop window with three lights and a centered title, a plain card, or nothing, for content that brings its own frame.
   - fade (default true): Fade the window's lower edge out behind the dock, the way the reference desktop sinks into the page. Turn it off to keep all of the content in view; the dock then sits under the window.
   - duration (default 0.3): Seconds a window takes to grow up out of its icon. The open one dissolves in step, so it's gone just before the new one lands.
   - hoverScale (default 1.1): The scale an icon grows to as it rises under the pointer. `1` keeps its size.

4. Don't change, in components/ui/launch-dock.tsx:
   - Windows animate only transform and opacity, as hardware animations on their own layers, and closing animates opacity alone; nothing repaints mid-flight.
   - The open window never moves: it dissolves in place under the new one (z-index 2 over 1), which is opaque from its first frame behind the icon, so two windows never cross or blend.
   - A pick measures its icon before any state changes, so the launch's first frame never waits on layout.
   - A launch turns round from wherever it is: a window still dissolving comes back in place instead of growing from its icon again.
   - Closed windows stay mounted, `hidden` and `inert`, as tabpanels of a tablist with a roving `tabIndex`, so their content and state survive a switch.
   Its timing is all in the TIMING block at the top of that file.

Docs: https://keyframeui.com/components/launch-dock.md

Studio Work

A design studio's clients as marks in the dock, each launching the site the studio built for them, address bar and all.

halden.house

Halden House · Website and identity, 2026

Take this demo to your coding agent.
Add this moment from KeyframeUI to our project and adapt it to our content.

Launch Dock: A dock of app icons under a window. Pick one and its window grows up out of the icon in 0.3s, over the open one, which dissolves where it is. One label glides over the dock as you point, and with autoplay the dot under the open app fills like a timer before the next one launches.
This demo, Studio Work: A design studio's clients as marks in the dock, each launching the site the studio built for them, address bar and all.

1. Install it:
   npx shadcn@latest add @keyframeui/launch-dock-studio-demo
   (If the CLI can't find @keyframeui, use https://keyframeui.com/r/launch-dock-studio-demo.json instead.)
   It adds the demo, components/launch-dock-studio-demo.tsx, and the component, components/ui/launch-dock.tsx.

2. Make it ours: our copy, data, images and colors. Keep the structure the motion depends on. If we only need the effect, use <LaunchDock> on its own.

3. These props set its feel. Change them before you change the file:
   - frame (default "window"): What the content sits in: a desktop window with three lights and a centered title, a plain card, or nothing, for content that brings its own frame.
   - fade (default true): Fade the window's lower edge out behind the dock, the way the reference desktop sinks into the page. Turn it off to keep all of the content in view; the dock then sits under the window.
   - duration (default 0.3): Seconds a window takes to grow up out of its icon. The open one dissolves in step, so it's gone just before the new one lands.
   - hoverScale (default 1.1): The scale an icon grows to as it rises under the pointer. `1` keeps its size.

4. Don't change, in components/ui/launch-dock.tsx:
   - Windows animate only transform and opacity, as hardware animations on their own layers, and closing animates opacity alone; nothing repaints mid-flight.
   - The open window never moves: it dissolves in place under the new one (z-index 2 over 1), which is opaque from its first frame behind the icon, so two windows never cross or blend.
   - A pick measures its icon before any state changes, so the launch's first frame never waits on layout.
   - A launch turns round from wherever it is: a window still dissolving comes back in place instead of growing from its icon again.
   - Closed windows stay mounted, `hidden` and `inert`, as tabpanels of a tablist with a roving `tabIndex`, so their content and state survive a switch.
   Its timing is all in the TIMING block at the top of that file.

Docs: https://keyframeui.com/components/launch-dock.md

Props

items Required

TypeLaunchDockItem[]

The apps, in dock order. Each one is { id, label, icon, content, title? }. label names it in the gliding label, the title bar and for screen readers; icon is clipped to the dock's rounded square, so a full-bleed <img> or SVG tile works; content is what its window shows, laid out at windowSize; title replaces the label in the title bar (a domain, a file name).

value

Typestring

The open app's id, when you control it. Pair it with onValueChange.

defaultValue

Typestring

The app that's open at first. Defaults to the first one.

onValueChange

Type(id: string, reason: "pick" | "autoplay") => void

Called with an app's id whenever it launches, and why: the visitor picked it (a click, a tap or a key), or autoplay moved on.

autoplay

Typeboolean | numberDefaultfalse

Launch the next app on its own every 4.5s until the visitor picks one. A number sets the time in ms. It pauses while a pointer is over the dock, focus is inside it, the tab is hidden or the dock is out of view, and stays off with reduced motion.

windowSize

Type[number, number]Default[960, 600]

The size each window's content is laid out at, in px. Narrower containers scale it down to fit, like a screenshot, so a layout built at this size keeps its proportions on a phone.

frame

Type"window" | "card" | "none"Default"window"

What the content sits in: a desktop window with three lights and a centered title, a plain card, or nothing, for content that brings its own frame.

fade

TypebooleanDefaulttrue

Fade the window's lower edge out behind the dock, the way the reference desktop sinks into the page. Turn it off to keep all of the content in view; the dock then sits under the window.

duration

TypenumberDefault0.3

Seconds a window takes to grow up out of its icon. The open one dissolves in step, so it's gone just before the new one lands.

hoverScale

TypenumberDefault1.1

The scale an icon grows to as it rises under the pointer. 1 keeps its size.

dockLabel

TypestringDefault"Apps"

The dock's accessible name, read out when focus enters it.

trayClassName

Typestring

Classes for the dock's surface: its fill, ring and shadow.

windowClassName

Typestring

Classes for each window's surface: its fill and ring.

className

Typestring

Extra classes for the root. Set [--launch-dock-roundness:0.5] for round icons, like faces; the dock's corners follow, and windows launch out of the circle.