Expandable Action Bar
beui/expandable-action-barFreeBlock
Compact icon actions that expand into labeled controls on hover or focus with shared layout motion.
Install it
npx shadcn@latest add https://beui.dev/r/expandable-action-bar.jsonSource
1"use client";2// beui.dev/components/blocks/expandable-action-bar34import { LayoutGroup, motion, useReducedMotion, type Transition } from "motion/react";5import {6 useCallback,7 useEffect,8 useId,9 useMemo,10 useRef,11 useState,12 type FocusEvent,13 type MouseEvent,14 type ReactNode,15} from "react";16import { cn } from "@/lib/utils";1718export type ExpandableActionBarSize = "sm" | "md";1920export type ExpandableActionBarItem = {21 id: string;22 label: ReactNode;23 icon: ReactNode;24 onClick?: () => void;25 disabled?: boolean;26 active?: boolean;27 badge?: ReactNode;28 shortcut?: ReactNode;29};3031export type ExpandableActionBarClassNames = {32 root?: string;33 track?: string;34 item?: string;35 activeItem?: string;36 icon?: string;37 label?: string;38 badge?: string;39 shortcut?: string;40};4142export interface ExpandableActionBarProps {43 items: ExpandableActionBarItem[];44 expanded?: boolean;45 defaultExpanded?: boolean;46 onExpandedChange?: (expanded: boolean) => void;47 activeId?: string;48 onAction?: (item: ExpandableActionBarItem) => void;49 size?: ExpandableActionBarSize;50 expandOnHover?: boolean;51 expandOnFocus?: boolean;52 collapseDelay?: number;53 className?: string;54 classNames?: ExpandableActionBarClassNames;55 renderItem?: (item: ExpandableActionBarItem, state: { expanded: boolean; active: boolean }) => ReactNode;56}5758const ITEM_TRANSITION: Transition = {59 type: "spring",60 stiffness: 460,61 damping: 34,62 mass: 0.62,63};6465const LABEL_TRANSITION: Transition = {66 type: "spring",67 stiffness: 380,68 damping: 32,69 mass: 0.7,70};7172const SIZE_CLASS: Record<ExpandableActionBarSize, string> = {73 sm: "min-h-9 gap-1 p-1 text-xs",74 md: "min-h-11 gap-1.5 p-1.5 text-sm",75};7677const ITEM_SIZE_CLASS: Record<ExpandableActionBarSize, string> = {78 sm: "h-7 min-w-7 px-1.5",79 md: "h-8 min-w-8 px-2",80};8182const ICON_SIZE_CLASS: Record<ExpandableActionBarSize, string> = {83 sm: "h-3.5 w-3.5",84 md: "h-4 w-4",85};8687function useControllableExpanded({88 expanded,89 defaultExpanded,90 onExpandedChange,91}: {92 expanded?: boolean;93 defaultExpanded?: boolean;94 onExpandedChange?: (expanded: boolean) => void;95}) {96 const [internalExpanded, setInternalExpanded] = useState(defaultExpanded ?? false);97 const isControlled = expanded !== undefined;98 const value = expanded ?? internalExpanded;99100 const setValue = useCallback(101 (next: boolean) => {102 if (!isControlled) setInternalExpanded(next);103 onExpandedChange?.(next);104 },105 [isControlled, onExpandedChange],106// … truncated
What it pulls in
npm packages
Files it writes
More from beui
All 104 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| File Upload Attachment Uploadattachment-upload | beui | Blocks | Free | 4 deps · 5 files | |
| Availability Scheduleravailability-scheduler | beui | Blocks | Free | 4 deps · 15 files | |
| Bloom Menubloom-menu | beui | Blocks | Free | 4 deps · 3 files | |
| Command Palettecommand-palette | beui | Blocks | Free | 4 deps · 3 files | |
| Dynamic Islanddynamic-island | beui | Blocks | Free | 3 deps · 3 files | |
| Expandable Tabsexpandable-tabs | beui | Blocks | Free | 3 deps · 3 files | |
| Feedback Widgetfeedback-widget | beui | Blocks | Free | 4 deps · 9 files | |
| File Upload Upload Queuefile-upload | beui | Blocks | Free | 4 deps · 3 files |
