Side Menu Component
Build slide-out panel components for quick-access tools
Side Menu Component
Side Menu components appear as slide-out panels from the side navigation. They're ideal for quick-access tools that users need frequently while working on other tasks.
When to Use
- Quick actions that don't need a full page
- Search or lookup tools
- Notification panels
- Utilities accessed from anywhere
Manifest Configuration
components:
- type: side-menu
title: "Quick Actions"
id: "quick-actions-uuid"
path: static/panel/build
settings:
icon: "lightning"
width: "M"Settings
| Setting | Type | Required | Values |
|---|---|---|---|
icon | string | Yes | Icon identifier |
width | string | Yes | S, M, or L |
icon
The icon shown in the side navigation. Common options:
| Icon | Use Case |
|---|---|
Lightning | Quick actions |
Search | Search tool |
Bell | Notifications |
Settings | Settings |
Calendar | Scheduling |
Help | Help/support |
See All IconsBrowse the complete icon library in the Design System Storybook.
width
The panel width when expanded:
| Value | Description | Use Case |
|---|---|---|
S | Small | Simple actions, toggles |
M | Medium | Forms, lists |
L | Large | Data tables, complex UI |
Context Access
Side Menu components have access to user context only — not record context:
import FireberryClientSDK from "@fireberry/sdk/client";
const client = new FireberryClientSDK();
await client.initializeContext();
const { user } = client.context;
console.log(user.id); // "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
console.log(user.fullName); // "John Doe"
// record is NOT available in Side Menu components
// client.context.record will be empty
ImportantIf your feature needs to know which record the user is viewing, use a Record Component instead.
Example: Quick Actions Panel
A panel with common actions:
import { useEffect, useState } from "react";
import FireberryClientSDK from "@fireberry/sdk/client";
import {
DSThemeContextProvider,
Typography,
Button,
List,
ListItem,
ListItemText,
} from "@fireberry/ds";
function QuickActionsPanel() {
const [client] = useState(() => new FireberryClientSDK());
const [recentItems, setRecentItems] = useState([]);
useEffect(() => {
async function init() {
await client.initializeContext();
// Fetch recent items
const result = await client.api.query(1, {
fields: "accountid,accountname",
query: `ownername = "${client.context.user.fullName}"`,
page_size: 5,
});
if (result.success) {
const items = Array.isArray(result.data) ? result.data : [result.data];
setRecentItems(items);
}
}
init();
}, [client]);
const createNew = async () => {
const result = await client.api.create(1, {
name: `New Item - ${new Date().toLocaleDateString()}`,
status: "draft",
});
if (result.success) {
alert("Created!");
}
};
return (
<DSThemeContextProvider isRtl={false}>
<div style={{ padding: 16 }}>
<Typography type="title">Quick Actions</Typography>
<div style={{ marginTop: 16 }}>
<Button
label="Create New"
color="success"
variant="primary"
onClick={createNew}
/>
</div>
<Typography type="subTitle" style={{ marginTop: 24 }}>
Recent Items
</Typography>
<List>
{recentItems.map((item) => (
<ListItem key={item.id}>
<ListItemText>{item.name}</ListItemText>
</ListItem>
))}
</List>
</div>
</DSThemeContextProvider>
);
}Example: Search Tool
A search interface in a Side Menu:
import { useState, useEffect } from "react";
import FireberryClientSDK from "@fireberry/sdk/client";
import {
DSThemeContextProvider,
Typography,
List,
ListItem,
ListItemText,
} from "@fireberry/ds";
function SearchPanel() {
const [client] = useState(() => new FireberryClientSDK());
const [query, setQuery] = useState("");
const [results, setResults] = useState([]);
const [searching, setSearching] = useState(false);
useEffect(() => {
client.initializeContext();
}, [client]);
const search = async () => {
if (!query.trim()) return;
setSearching(true);
const result = await client.api.query(1, {
fields: "accountid,accountname,status",
query: `accountname LIKE "${query}%"`,
page_size: 10,
});
if (result.success) {
const items = Array.isArray(result.data) ? result.data : [result.data];
setResults(items);
}
setSearching(false);
};
return (
<DSThemeContextProvider isRtl={false}>
<div style={{ padding: 16 }}>
<Typography type="title">Search</Typography>
<div style={{ marginTop: 16, display: "flex", gap: 8 }}>
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
onKeyPress={(e) => e.key === "Enter" && search()}
placeholder="Search..."
style={{
flex: 1,
padding: "8px 12px",
border: "1px solid #E2E3E9",
borderRadius: 4,
}}
/>
<button onClick={search}>Search</button>
</div>
{searching && <Typography type="caption">Searching...</Typography>}
{results.length > 0 && (
<List>
{results.map((item) => (
<ListItem key={item.id}>
<ListItemText>{item.name}</ListItemText>
</ListItem>
))}
</List>
)}
</div>
</DSThemeContextProvider>
);
}Width Guidelines
| Width | Best For |
|---|---|
| Small (S) | Action buttons, quick toggles, simple status |
| Medium (M) | Search, short lists, forms |
| Large (L) | Data tables, detailed lists, complex forms |
TipStart with Medium. Only go Large if your content genuinely needs the space.
Use Cases
| Use Case | Suggested Width |
|---|---|
| Quick action buttons | S |
| Search tool | M |
| Recent items list | M |
| Notification feed | M |
| Settings panel | M or L |
| Data browser | L |
Validation Errors
| Error | Solution |
|---|---|
icon is required | Add icon to settings |
width must be S, M, or L | Use S, M, or L |
Next Steps
- Record Component — Components with record context
- Global Menu Component — Full-page views
- SDK — Learn more about context and API
Updated 4 days ago
