Expanding Toggle Button
ericts-ui/expanding-toggle-buttonFreeComponent
A shadcn toggle button that expands from an icon into an icon-and-label action while keeping the icon anchored.
Live preview
live · rendered by the registry
Rendered by ericts-ui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://ui.ericts.com/r/expanding-toggle-button.jsonSource
1"use client";23import * as React from "react";4import {5 animate,6 motion,7 useReducedMotion,8 type Transition,9} from "motion/react";1011import { Button } from "@/components/ui/button";12import { cn } from "@/lib/utils";1314type ButtonProps = React.ComponentPropsWithoutRef<typeof Button>;15type ButtonClickEvent = Parameters<NonNullable<ButtonProps["onClick"]>>[0];16type ExpandingToggleButtonSize = "default" | "xs" | "sm" | "lg";1718const COLLAPSED_WIDTH: Record<ExpandingToggleButtonSize, number> = {19 default: 32,20 xs: 24,21 sm: 28,22 lg: 36,23};2425const ICON_SIZE: Record<ExpandingToggleButtonSize, number> = {26 default: 16,27 xs: 12,28 sm: 14,29 lg: 18,30};3132const LABEL_OUTER_PADDING: Record<ExpandingToggleButtonSize, number> = {33 default: 10,34 xs: 8,35 sm: 10,36 lg: 10,37};3839const LABEL_ICON_GAP = 6;4041const MORPH_TRANSITION: Transition = {42 duration: 0.2,43 ease: [0.22, 1, 0.36, 1],44};4546const REDUCED_TRANSITION: Transition = { duration: 0 };47const useIsomorphicLayoutEffect =48 typeof window === "undefined" ? React.useEffect : React.useLayoutEffect;4950export type ExpandingToggleButtonProps = Omit<51 ButtonProps,52 | "aria-label"53 | "aria-pressed"54 | "children"55 | "onClick"56 | "size"57 | "style"58> & {59 /** Controlled active state. */60 active?: boolean;61 /** Initial active state for uncontrolled usage. */62 defaultActive?: boolean;63 /** Called after the button requests an active-state change. */64 onActiveChange?: (active: boolean) => void;65 /** Icon shown while the button is inactive. */66 icon: React.ReactNode;67 /** Optional icon shown while the button is active. */68 activeIcon?: React.ReactNode;69 /** Content revealed while the button is active. */70 label: React.ReactNode;71 /** Accessible name used while the button is inactive. */72 inactiveLabel: string;73 /** Accessible name used while the button is active. */74 activeLabel: string;75 /** Direction the label grows toward while the icon stays anchored. */76 expandFrom?: "start" | "end";77 /** Text-button size; the inactive width matches its icon-only counterpart. */78 size?: ExpandingToggleButtonSize;79 onClick?: (event: ButtonClickEvent) => void;80};8182export const ExpandingToggleButton = React.forwardRef<83 HTMLButtonElement,84 ExpandingToggleButtonProps85>(function ExpandingToggleButton(86 {87 active,88 defaultActive = false,89 onActiveChange,90 icon,91 activeIcon,92 label,93 inactiveLabel,94 activeLabel,95 expandFrom = "end",96 variant = "outline",97 size = "lg",98// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from ericts-ui
All 33 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Adaptive Draweradaptive-drawer | ericts-ui | Components | Free | 2 deps | |
| Check Animationcheck-animation | ericts-ui | Components | Free | no deps · 2 files | |
| Context Cursorcontext-cursor | ericts-ui | Components | Free | 1 dep | |
| Copy Buttoncopy-button | ericts-ui | Components | Free | 2 deps | |
| Expandable Dialogexpandable-modal | ericts-ui | Components | Free | 1 dep | |
| Expandable Tabsexpandable-tabs | ericts-ui | Components | Free | 1 dep | |
| Expandable Toolbarexpandable-toolbar | ericts-ui | Components | Free | 1 dep | |
| Expanding Panelexpanding-panel | ericts-ui | Components | Free | 2 deps |
