- Accordion
- Alert
- Avatar
- Badge
- Breadcrumb
- Button
- Button Group
- Calendarnew
- Card
- Carousel
- Checkbox
- Chip
- Collapse
- Dialog
- Drawer
- Footer
- Gallery
- Icon Button
- Image
- Input
- List
- Mapnew
- Menu
- Navbar
- Pagination
- Popover
- Progress
- Radio
- Rating
- Select
- Sidebar
- Skeletonnew
- Slider
- Software Purchase Card
- Sonner / Toastnew
- Speed Dial
- Spinner
- Stepper
- Switch
- Table
- Tabs
- Textarea
- Timeline
- Tooltip
- Typography
- Video
"use client"
import * as React from "react"
import { Home, LayoutDashboard, Plus, Settings } from "lucide-react"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip"
export function SpeedDialDemo() {
const [open, setOpen] = React.useState(false)
return (
<TooltipProvider>
<Tooltip open={open} onOpenChange={setOpen}>
<TooltipTrigger asChild>
<Button
size="icon"
className="rounded-full"
onClick={() => setOpen(!open)}
>
<Plus
className={cn(
"h-[18px] w-[18px] transition-transform",
open && "rotate-45"
)}
/>
</Button>
</TooltipTrigger>
<TooltipContent
side="left"
sideOffset={8}
className="flex flex-col gap-2 border-0 bg-transparent p-0 shadow-none [&>svg]:hidden"
>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full"
>
<Home className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
<TooltipContent
side="left"
sideOffset={8}
className="[&>svg]:hidden"
>
Home
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full"
>
<Settings className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
<TooltipContent
side="left"
sideOffset={8}
className="[&>svg]:hidden"
>
Settings
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full"
>
<LayoutDashboard className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
<TooltipContent
side="left"
sideOffset={8}
className="[&>svg]:hidden"
>
Dashboard
</TooltipContent>
</Tooltip>
</TooltipProvider>
</TooltipContent>
</Tooltip>
</TooltipProvider>
)
}
Installation
pnpm dlx @creative-tim/ui@latest add tooltip button
Usage
import SpeedDialDemo from "@/components/speed-dial-demo"<SpeedDialDemo />Examples
Speed Dial Custom Icon
A speed dial with a custom icon (mail) as the main trigger button, demonstrating how to use different icons for the primary action button.
"use client"
import * as React from "react"
import { Home, LayoutDashboard, Mail, Settings } from "lucide-react"
import { Button } from "@/components/ui/button"
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip"
export function SpeedDialCustomIcon() {
const [open, setOpen] = React.useState(false)
return (
<TooltipProvider>
<Tooltip open={open} onOpenChange={setOpen}>
<TooltipTrigger asChild>
<Button
size="icon"
className="rounded-full"
onClick={() => setOpen(!open)}
>
<Mail className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
<TooltipContent
side="left"
sideOffset={8}
className="flex flex-col gap-2 border-0 bg-transparent p-0 shadow-none [&>svg]:hidden"
>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full"
>
<Home className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
<TooltipContent
side="left"
sideOffset={8}
className="[&>svg]:hidden"
>
Home
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full"
>
<Settings className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
<TooltipContent
side="left"
sideOffset={8}
className="[&>svg]:hidden"
>
Settings
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full"
>
<LayoutDashboard className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
<TooltipContent
side="left"
sideOffset={8}
className="[&>svg]:hidden"
>
Dashboard
</TooltipContent>
</Tooltip>
</TooltipProvider>
</TooltipContent>
</Tooltip>
</TooltipProvider>
)
}
Speed Dial Horizontal
A speed dial with a horizontal layout where action buttons are arranged side by side instead of vertically stacked, ideal for wider screen spaces.
"use client"
import * as React from "react"
import { Home, LayoutDashboard, Plus, Settings } from "lucide-react"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip"
export function SpeedDialHorizontal() {
const [open, setOpen] = React.useState(false)
return (
<TooltipProvider>
<Tooltip open={open} onOpenChange={setOpen}>
<TooltipTrigger asChild>
<Button
size="icon"
className="rounded-full"
onClick={() => setOpen(!open)}
>
<Plus
className={cn(
"h-[18px] w-[18px] transition-transform",
open && "rotate-45"
)}
/>
</Button>
</TooltipTrigger>
<TooltipContent
side="right"
sideOffset={8}
className="flex gap-2 border-0 bg-transparent p-0 shadow-none [&>svg]:hidden"
>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full"
>
<Home className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
<TooltipContent sideOffset={8} className="[&>svg]:hidden">
Home
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full"
>
<Settings className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
<TooltipContent sideOffset={8} className="[&>svg]:hidden">
Settings
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full"
>
<LayoutDashboard className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
<TooltipContent sideOffset={8} className="[&>svg]:hidden">
Dashboard
</TooltipContent>
</Tooltip>
</TooltipProvider>
</TooltipContent>
</Tooltip>
</TooltipProvider>
)
}
Speed Dial Placement
A demonstration of speed dial placement options showing how speed dials can be positioned in different corners of a container (top-left, top-right, bottom-left, bottom-right) with appropriate tooltip positioning.
"use client"
import * as React from "react"
import { Home, LayoutDashboard, Plus, Settings } from "lucide-react"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip"
export function SpeedDialPlacement() {
const [open1, setOpen1] = React.useState(false)
const [open2, setOpen2] = React.useState(false)
const [open3, setOpen3] = React.useState(false)
const [open4, setOpen4] = React.useState(false)
return (
<div className="relative h-80 w-full">
<div className="absolute top-0 left-0">
<TooltipProvider>
<Tooltip open={open1} onOpenChange={setOpen1}>
<TooltipTrigger asChild>
<Button
size="icon"
className="rounded-full"
onClick={() => setOpen1(!open1)}
>
<Plus
className={cn(
"h-[18px] w-[18px] transition-transform",
open1 && "rotate-45"
)}
/>
</Button>
</TooltipTrigger>
<TooltipContent
side="bottom"
sideOffset={8}
className="flex flex-col gap-2 border-0 bg-transparent p-0 shadow-none [&>svg]:hidden"
>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full"
>
<Home className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
<TooltipContent
side="left"
sideOffset={8}
className="[&>svg]:hidden"
>
Home
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full"
>
<Settings className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
<TooltipContent
side="left"
sideOffset={8}
className="[&>svg]:hidden"
>
Settings
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full"
>
<LayoutDashboard className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
<TooltipContent
side="left"
sideOffset={8}
className="[&>svg]:hidden"
>
Dashboard
</TooltipContent>
</Tooltip>
</TooltipProvider>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
<div className="absolute top-0 right-0">
<TooltipProvider>
<Tooltip open={open2} onOpenChange={setOpen2}>
<TooltipTrigger asChild>
<Button
size="icon"
className="rounded-full"
onClick={() => setOpen2(!open2)}
>
<Plus
className={cn(
"h-[18px] w-[18px] transition-transform",
open2 && "rotate-45"
)}
/>
</Button>
</TooltipTrigger>
<TooltipContent
side="left"
sideOffset={8}
className="flex gap-2 border-0 bg-transparent p-0 shadow-none [&>svg]:hidden"
>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full"
>
<Home className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
<TooltipContent
side="top"
sideOffset={8}
className="[&>svg]:hidden"
>
Home
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full"
>
<Settings className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
<TooltipContent
side="top"
sideOffset={8}
className="[&>svg]:hidden"
>
Settings
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full"
>
<LayoutDashboard className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
<TooltipContent
side="top"
sideOffset={8}
className="[&>svg]:hidden"
>
Dashboard
</TooltipContent>
</Tooltip>
</TooltipProvider>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
<div className="absolute bottom-0 left-0">
<TooltipProvider>
<Tooltip open={open3} onOpenChange={setOpen3}>
<TooltipTrigger asChild>
<Button
size="icon"
className="rounded-full"
onClick={() => setOpen3(!open3)}
>
<Plus
className={cn(
"h-[18px] w-[18px] transition-transform",
open3 && "rotate-45"
)}
/>
</Button>
</TooltipTrigger>
<TooltipContent
side="right"
sideOffset={8}
className="flex gap-2 border-0 bg-transparent p-0 shadow-none [&>svg]:hidden"
>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full"
>
<Home className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
<TooltipContent sideOffset={8} className="[&>svg]:hidden">
Home
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full"
>
<Settings className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
<TooltipContent sideOffset={8} className="[&>svg]:hidden">
Settings
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full"
>
<LayoutDashboard className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
<TooltipContent sideOffset={8} className="[&>svg]:hidden">
Dashboard
</TooltipContent>
</Tooltip>
</TooltipProvider>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
<div className="absolute right-0 bottom-0">
<TooltipProvider>
<Tooltip open={open4} onOpenChange={setOpen4}>
<TooltipTrigger asChild>
<Button
size="icon"
className="rounded-full"
onClick={() => setOpen4(!open4)}
>
<Plus
className={cn(
"h-[18px] w-[18px] transition-transform",
open4 && "rotate-45"
)}
/>
</Button>
</TooltipTrigger>
<TooltipContent
side="top"
sideOffset={8}
className="flex flex-col gap-2 border-0 bg-transparent p-0 shadow-none [&>svg]:hidden"
>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full"
>
<Home className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
<TooltipContent
side="left"
sideOffset={8}
className="[&>svg]:hidden"
>
Home
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full"
>
<Settings className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
<TooltipContent
side="left"
sideOffset={8}
className="[&>svg]:hidden"
>
Settings
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full"
>
<LayoutDashboard className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
<TooltipContent
side="left"
sideOffset={8}
className="[&>svg]:hidden"
>
Dashboard
</TooltipContent>
</Tooltip>
</TooltipProvider>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
</div>
)
}
Speed Dial with Custom Styles
A speed dial with custom styling including rounded borders, background colors, and padding, demonstrating how to customize the appearance to match your design system.
"use client"
import * as React from "react"
import { Home, LayoutDashboard, Plus, Settings } from "lucide-react"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip"
export function SpeedDialWithCustomStyles() {
const [open, setOpen] = React.useState(false)
return (
<TooltipProvider>
<Tooltip open={open} onOpenChange={setOpen}>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full"
onClick={() => setOpen(!open)}
>
<Plus
className={cn(
"h-[18px] w-[18px] transition-transform",
open && "rotate-45"
)}
/>
</Button>
</TooltipTrigger>
<TooltipContent
side="left"
sideOffset={8}
className="bg-background flex flex-col gap-2 rounded-full border p-1 shadow-none [&>svg]:hidden"
>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full p-3"
>
<Home className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full p-3"
>
<Settings className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="rounded-full p-3"
>
<LayoutDashboard className="h-[18px] w-[18px]" />
</Button>
</TooltipTrigger>
</Tooltip>
</TooltipProvider>
</TooltipContent>
</Tooltip>
</TooltipProvider>
)
}
Speed Dial with Label
A speed dial with always-visible tooltip labels on the action buttons, providing immediate context without requiring hover interactions.
"use client"
import * as React from "react"
import { Home, LayoutDashboard, Plus, Settings } from "lucide-react"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip"
export function SpeedDialWithLabel() {
const [open, setOpen] = React.useState(false)
return (
<TooltipProvider>
<Tooltip open={open} onOpenChange={setOpen}>
<TooltipTrigger asChild>
<Button
size="icon"
className="rounded-full"
onClick={() => setOpen(!open)}
>
<Plus
className={cn(
"h-[18px] w-[18px] transition-transform duration-200",
open && "rotate-45"
)}
/>
</Button>
</TooltipTrigger>
<TooltipContent
side="left"
sideOffset={8}
className="flex flex-col gap-3 border-0 bg-transparent p-0 shadow-none [&>svg]:hidden"
>
<div className="animate-in fade-in-0 slide-in-from-right-2 flex items-center gap-3 transition-all duration-200">
<Button
size="icon"
variant="secondary"
className="shrink-0 rounded-full"
>
<Home className="h-[18px] w-[18px]" />
</Button>
<span className="bg-background text-foreground rounded-md border px-3 py-1.5 text-sm font-medium whitespace-nowrap shadow-sm">
Home
</span>
</div>
<div className="animate-in fade-in-0 slide-in-from-right-2 flex items-center gap-3 transition-all delay-75 duration-200">
<Button
size="icon"
variant="secondary"
className="shrink-0 rounded-full"
>
<Settings className="h-[18px] w-[18px]" />
</Button>
<span className="bg-background text-foreground rounded-md border px-3 py-1.5 text-sm font-medium whitespace-nowrap shadow-sm">
Settings
</span>
</div>
<div className="animate-in fade-in-0 slide-in-from-right-2 flex items-center gap-3 transition-all delay-150 duration-200">
<Button
size="icon"
variant="secondary"
className="shrink-0 rounded-full"
>
<LayoutDashboard className="h-[18px] w-[18px]" />
</Button>
<span className="bg-background text-foreground rounded-md border px-3 py-1.5 text-sm font-medium whitespace-nowrap shadow-sm">
Dashboard
</span>
</div>
</TooltipContent>
</Tooltip>
</TooltipProvider>
)
}
Best Practices
- Use speed dials for quick access to frequently used actions
- Keep the number of action buttons to 3-5 for optimal usability
- Position speed dials in corners or fixed positions to avoid interfering with content
- Use clear, recognizable icons for action buttons
- Provide tooltips or labels for better accessibility
- Consider using horizontal layout for wider screens
- Use animations to indicate state changes (open/closed)
- Ensure speed dials don't obstruct important content
- Use custom styles to match your design system
- Consider mobile responsiveness when positioning speed dials
Speed dial components provide an elegant way to organize multiple actions in a compact floating button interface. They're ideal for dashboards, mobile apps, and any interface where space is limited but quick access to actions is important.