Fold Toolbar
NewCustomize
Right
Size40px
Radius12px
Duration0.35s
Accent
Installation
npx shadcn@latest add https://uibrik.com/r/fold-toolbar.jsonInstall the packages
npm install @tabler/icons-react motion react-use-measureAdd the cn helper
Imports
cnfrom@/lib/utils, whichshadcn initcreates. Add it by hand without shadcn.Copy the source into your project
components/uibrik/fold-toolbar/fold-toolbar.tsx"use client"; import { useEffect, useId, useRef, useState, type KeyboardEvent, type ReactNode } from "react"; import { AnimatePresence, MotionConfig, motion } from "motion/react"; import useMeasure from "react-use-measure"; import { IconX } from "@tabler/icons-react"; import { cn } from "@/lib/utils"; // Fold-out toolbar. At rest it's one icon button showing the current tool, // with a small notch in its corner saying there's more inside. Pressing it // unfolds a tray of tools along one side, pushing whatever sits next to it out // of the way. Picking a tool folds the tray back into the button. // // The picked tool is one object that morphs between the button and its slot: // opening, its icon leaves the button and travels out to its place in the tray // as its tile fills in; closing, it travels back and hands over to the button // in the last frames, same spot and colour, so there's no visible swap. It // rides the same spring as the tray's edge, which it never outruns, so it's // never clipped. The other tools stay put and settle in as the edge reaches // them. The tray's real width (or height) springs, measured from the row, so // nothing inside is ever scaled. One highlight slides between tools on hover. Escape or a press outside folds // it without a choice; arrow keys move between the tools. export type FoldTool = { value: string; label: string; icon: ReactNode; disabled?: boolean };
Adds the files to
components/uibrik/fold-toolbar and installs @tabler/icons-react, motion and react-use-measure. With the @uibrik namespace set up: npx shadcn@latest add @uibrik/fold-toolbar.Usage
import { FoldToolbar } from "@/components/uibrik/fold-toolbar/fold-toolbar";const tools = [ { value: "square", label: "Rectangle", icon: <IconSquare stroke={1.75} /> }, { value: "circle", label: "Ellipse", icon: <IconCircle stroke={1.75} /> }, // …3 more];<FoldToolbar tools={tools} label="Shapes" direction="right" size={40} radius={12} duration={0.35} accent="#3b82f6" closeOnSelect defaultOpen={false} // value="…" // onChange={(value) => {}} // defaultValue="…" // open={false} // onOpenChange={(open) => {}}/>Props
FoldToolbar- direction
- Type "right" | "left" | "down" | "up"
- "right"
- Side the tray unfolds toward. Phones switch the demo to a vertical bar.
- size
- Type number
- 40
- Size of the button and of every tool.
- radius
- Type number
- 12
- Corner radius of the buttons; the tray's runs parallel to it.
- duration
- Type number
- 0.35
- How long the tray takes to unfold.
- accent
- Type string
- "#3b82f6"
- Fill behind the picked tool; empty gives a neutral tint.
- closeOnSelect
- Type boolean
- true
- Fold back as soon as a tool is picked.
- toolsrequired
- Type { value; label; icon; disabled? }[]
- –
- Tools in the tray, in order from the button.
- labelrequired
- Type string
- –
- Names the toolbar for screen readers.
- value / onChange
- Type string / (value) => void
- –
- Controlled pick.
- defaultValue
- Type string
- –
- Pick on mount when uncontrolled. Defaults to the first tool.
- open / onOpenChange
- Type boolean / (open) => void
- –
- Controlled unfold, e.g. to keep only one tray open at a time.
- defaultOpen
- Type boolean
- false
- Unfolded on mount when uncontrolled.
- className
- Type string
- –
- Classes for the tray.