Expandable Dock
scrollxui/expandable-dockFreeComponent
A customizable expandable dock component.
Live preview
live · rendered by the registry
Rendered by scrollxui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://scrollxui.dev/registry/expandable-dock.jsonSource
1'use client';23import React, { useState, ReactNode, useRef, useEffect } from 'react';4import { motion } from 'motion/react';5import { cn } from '@/lib/utils';67interface ExpandableDockProps {8 headerContent: ReactNode;9 children: ReactNode;10 className?: string;11}1213const ExpandableDock = ({14 headerContent,15 children,16 className,17}: ExpandableDockProps) => {18 const [animationStage, setAnimationStage] = useState<19 | 'collapsed'20 | 'widthExpanding'21 | 'heightExpanding'22 | 'fullyExpanded'23 | 'contentFadingOut'24 | 'heightCollapsing'25 | 'widthCollapsing'26 >('collapsed');2728 const containerRef = useRef<HTMLDivElement>(null);2930 const handleExpand = () => {31 setAnimationStage('widthExpanding');32 setTimeout(() => setAnimationStage('heightExpanding'), 400);33 setTimeout(() => setAnimationStage('fullyExpanded'), 850);34 };3536 const handleCollapse = () => {37 setAnimationStage('contentFadingOut');38 setTimeout(() => setAnimationStage('heightCollapsing'), 250);39 setTimeout(() => setAnimationStage('widthCollapsing'), 650);40 setTimeout(() => setAnimationStage('collapsed'), 1050);41 };4243 const isCollapsed = animationStage === 'collapsed';44 const isExpanded = animationStage === 'fullyExpanded';4546 useEffect(() => {47 const handleClickOutside = (e: MouseEvent) => {48 if (49 containerRef.current &&50 !containerRef.current.contains(e.target as Node) &&51 isExpanded52 ) {53 handleCollapse();54 }55 };56 document.addEventListener('mousedown', handleClickOutside);57 return () => document.removeEventListener('mousedown', handleClickOutside);58 }, [isExpanded]);5960 return (61 <div className='fixed bottom-8 left-1/2 -translate-x-1/2 z-50 w-full px-4 sm:px-0'>62 <motion.div63 ref={containerRef}64 initial={{65 width: 'min(90vw, 360px)',66 height: 68,67 borderRadius: 999,68 }}69 animate={{70 width:71 animationStage === 'collapsed' ||72 animationStage === 'widthCollapsing'73 ? 'min(90vw, 360px)'74 : 'min(90vw, 720px)',75 height:76 animationStage === 'collapsed' ||77 animationStage === 'widthExpanding' ||78 animationStage === 'widthCollapsing'79 ? 6880 : 'min(80vh, 500px)',81 borderRadius: isCollapsed ? 999 : 20,82 }}83 transition={{84 width: { duration: 0.45, ease: [0.4, 0, 0.2, 1] },85// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from scrollxui
All 180 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | scrollxui | Components | Free | 4 deps | |
| Alert Dialogalert-dialog | scrollxui | Components | Free | 7 deps | |
| Animated Buttonanimated-button | scrollxui | Components | Free | 4 deps | |
| Animated Tabsanimated-tabs | scrollxui | Components | Free | 1 dep | |
| Animated Testimonialsanimated-testimonials | scrollxui | Components | Free | 2 deps | |
| Animated TextGenerateanimated-textgenerate | scrollxui | Components | Free | 3 deps | |
| Announcementannouncement | scrollxui | Components | Free | 5 deps | |
| Aspect Ratioaspect-ratio | scrollxui | Components | Free | 1 dep |
