Search, Notifications & User Menu
Tapping search opens a full search overlay seeded with what you typed; the bell and the avatar each open their own menu — never both at once.
<SearchModal> + <NotificationsMenu> + <UserMenu>searchmodalnotificationsuser-menuavatar9:41
In this demo
Nimbus — knowledge base
What to try
- Tap the search field — the modal opens with your text
- Open the bell — unread items, mark all read
- Open the avatar menu — the bell menu closes itself
Code
app.tsx
import { AppShell, Header, Content, SearchField, SearchModal, NotificationsMenu, NotificationItem, UserMenu, UserMenuItem, MotionProvider, useSearchShortcut } from "appshell-react";
import { framerMotionAdapter } from "appshell-react/motion-framer";
import { LogOut, MessageSquare, Rocket, Settings, User } from "lucide-react";
import { useState } from "react";
export default function App() {
const [query, setQuery] = useState("");
const [searchOpen, setSearchOpen] = useState(false);
const [unread, setUnread] = useState(2);
// ⌘K on macOS, Ctrl+K elsewhere — SearchField's shortcutHint shows whichever applies
useSearchShortcut(() => setSearchOpen(true));
return (
<MotionProvider adapter={framerMotionAdapter}>
<AppShell safeArea>
<Header
behavior="sticky"
logo={<span className="font-bold">Nimbus</span>}
actions={
<>
{/* Bell and avatar coexist — opening one closes the other. */}
<NotificationsMenu
unreadCount={unread}
action={<button onClick={() => setUnread(0)}>Mark all read</button>}
>
<NotificationItem icon={<Rocket />} title="Deploy finished" time="2m" unread />
<NotificationItem icon={<MessageSquare />} title="Mara mentioned you" time="1h" unread />
</NotificationsMenu>
<UserMenu username="Mara Kealoha" detail="mara@nimbus.app" initials="MK">
<UserMenuItem icon={<User />} label="Profile" />
<UserMenuItem icon={<Settings />} label="Settings" />
<UserMenuItem icon={<LogOut />} label="Log out" destructive />
</UserMenu>
</>
}
searchContent={
<SearchField
placeholder="Search articles"
value={query}
onChange={setQuery}
onClick={() => setSearchOpen(true)} // tapping search opens the modal
shortcutHint="⌘K" // or "Ctrl K" — resolve from navigator.platform
/>
}
/>
<Content>{/* article list */}</Content>
<SearchModal
open={searchOpen}
onClose={() => setSearchOpen(false)}
defaultQuery={query} // optional: hand over what was typed
placeholder="Search the knowledge base"
>
{(q) => <Results query={q} />} {/* results are fully yours */}
</SearchModal>
</AppShell>
</MotionProvider>
);
}