Notion Floating Action Menu

A faithful Notion-inspired quick-create menu with a compact action panel and an animated compose-to-close interaction.

Installation

Pro components require registry authentication. Add your Unlumen UI Pro key as UNLUMEN_LICENSE_KEY in your .env.local file and follow the setup guide.

File Structure

notion-floating-action-menu.tsx

Usage

import { FileText, MessageCircle, Mic, Table2 } from "lucide-react";

import {
  NotionFloatingActionMenu,
  type NotionFloatingActionMenuItem,
} from "@/components/unlumen-ui/notion-floating-action-menu";

const actions: NotionFloatingActionMenuItem[] = [
  { value: "page", label: "Page", icon: <FileText /> },
  { value: "discussion", label: "Chat", icon: <MessageCircle /> },
  { value: "ai-notes", label: "AI Meeting Notes", icon: <Mic /> },
  { value: "database", label: "Database", icon: <Table2 /> },
];

export default function Example() {
  return (
    <NotionFloatingActionMenu
      items={actions}
      onItemSelect={(item) => console.log(item.value)}
    />
  );
}

API Reference

NotionFloatingActionMenu

PropTypeDefaultDescription
itemsNotionFloatingActionMenuItem[]-Actions rendered in the floating menu.
open?boolean-Controlled open state of the menu.
defaultOpen?booleanfalseInitial open state when the component is uncontrolled.
onOpenChange?(open: boolean) => void-Called whenever the menu opens or closes.
onItemSelect?(item: NotionFloatingActionMenuItem) => void-Called after an enabled action is selected.
align?"start" | "end""start"Aligns the menu with the start or end edge of the trigger.
menuOffset?number8Gap in pixels between the trigger and menu.
menuWidth?number180Width of the expanded menu in pixels.
closeOnSelect?booleantrueCloses the menu after an enabled action is selected.
triggerLabel?string"Open quick actions"Accessible label used while the menu is closed.
closeLabel?string"Close quick actions"Accessible label used while the menu is open.
triggerIcon?React.ReactNode-Custom icon displayed while the menu is closed.
closeIcon?React.ReactNode-Custom icon displayed while the menu is open.
springStiffness?number520Spring stiffness used by the panel, actions, and trigger.
springDamping?number40Spring damping used by the panel, actions, and trigger.
menuClassName?string-Additional classes applied to the floating menu panel.
itemClassName?string-Additional classes applied to every action.
className?string-Additional classes applied to the root element.

NotionFloatingActionMenuItem

PropTypeDefaultDescription
valuestring-Unique value identifying the action.
labelstring-Visible action label.
iconReact.ReactNode-Icon rendered before the label.
href?string-Optional link destination. Items without one render as buttons.
disabled?booleanfalsePrevents selection and exposes the disabled state.
onSelect?(item: NotionFloatingActionMenuItem) => void-Callback scoped to this action.
target?React.HTMLAttributeAnchorTarget-Anchor target used when href is provided.
rel?string-Anchor relationship used when href is provided.

Notes

  • The panel opens with a short, restrained spring and staggered action reveal, echoing Notion's sidebar quick-create menu.
  • Escape closes the menu and restores focus to the trigger. Arrow keys, Home, and End move between enabled actions.
  • Clicking outside closes the menu. Reduced-motion preferences preserve every state change without scale, travel, blur, or stagger.
  • Use the controlled open prop when the menu state needs to follow application state.

Credits

Built by leo.

The interaction is inspired by Notion's sidebar quick-create menu and SwiftUI's zoom-style transitions.

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.