Motion Tabs Menu
A floating bottom tab bar with animated width expansion, direction-aware content transitions, and spring-driven tap feedback.
Installation
CLI installation is not available for Pro components.
File Structure
motion-tabs-menu.tsx
Usage
import MotionTabsMenu from "@/components/unlumen-ui/motion-tabs-menu";
export default function Page() {
return (
<div className="flex min-h-screen items-center justify-center">
<MotionTabsMenu />
</div>
);
}API Reference
This component is fully self-contained and exposes no props. All demo data, tab content, and internal state are managed internally.
Notes
- Dynamic width — the toolbar width is computed from the number of buttons, gaps, and padding rather than hardcoded. When a tab becomes active, the active label's character count is used to derive the extra horizontal space, so the container never over- or under-shoots.
- Label delay — the active tab label fades in 80 ms after the width animation starts, giving the container a head start before the text appears. This is achieved by spreading
springTransitionand overridingdelay: 0.08on the label'smotion.span. - Direction-aware slides — switching between tabs sets a
directionvalue (+1or−1) that drives thecustomprop ofcontentVariants, so content always slides in from the correct side. - Height measurement —
react-use-measureattaches aResizeObserverto the content wrapper and feeds the live height into the spring animation, so the container snaps to the exact content size with no hardcoded values. AnimatePresence mode="popLayout"— exiting panels are removed from layout flow immediately, preventing double-height artifacts while two panels overlap during a tab switch.- Tap feedback —
whileTapapplies a vertical squish (scaleY: 0.8) to each button on press, with an automatic spring return on release. - Click-outside collapse — a native
mousedownlistener on acontainerRefcloses the expanded panel without any third-party hook.
Credits
Built by leo.
Inspired by Skiper UI.
Keep in mind
Most components on this site are inspired by or recreated from existing work across the web. I'm not here to take credit; just to learn, experiment, and sometimes push things a bit further. If something looks familiar and I forgot to mention you, reach out and I'll fix that right away.