When to Use
A fixed-width side panel for editing selected items while keeping the main canvas visible.
Use When
- • Editing block properties in a visual builder
- • Inspecting selected items while canvas stays visible
- • Need permanent side panel that doesn't overlay content
Skip When
- • No persistent selection model (use overlay mode for forms)
Size Variants
Choose normal for compact properties, wide for rich editing controls.
| Size | Width | Use Case |
|---|---|---|
normal | 448px | Simple properties, minimal controls |
wide | 512px | Rich editing, multiple sections |
Full Mode
Provide title, description, and children. Panel handles header, scrolling, and footer automatically.
Main Content Area
PropertyPanel stays visible while editing
Container Mode
Use subcomponents directly when you need full control over layout and structure.
Main Content Area
Empty State
Show when nothing is selected or when selection has no editable properties.
Main Content Area
PropertyPanelFooter
Standardized footer with enforced button patterns. Uses action props instead of children for consistent styling and layout.
Layout Rules
1 action: [Primary 100%]
2 actions: [Secondary 50%][Primary 50%]
3 actions: [Delete 33%][Secondary 33%][Primary 33%]
Two-button layout (Secondary + Primary)
Most common pattern: Cancel and Save actions.
<PropertyPanelFooter
secondaryAction={{ label: 'Cancel', onClick: handleCancel }}
primaryAction={{ label: 'Save', onClick: handleSave }}
/>Three-button layout (Delete + Secondary + Primary)
For editing existing items that can be deleted.
<PropertyPanelFooter
deleteAction={{ label: 'Delete', onClick: handleDelete }}
secondaryAction={{ label: 'Cancel', onClick: handleCancel }}
primaryAction={{ label: 'Save', onClick: handleSave }}
/>Primary only
Single action fills full width. Good for simple confirmations.
<PropertyPanelFooter
primaryAction={{ label: 'Done', onClick: handleDone }}
/>Loading states
Show loading spinners during async operations. Disabled states prevent interaction.
<PropertyPanelFooter
deleteAction={{ label: 'Delete', onClick: handleDelete, loading: isDeleting }}
secondaryAction={{ label: 'Cancel', onClick: handleCancel, disabled: isBusy }}
primaryAction={{ label: 'Saving...', onClick: handleSave, loading: isSaving }}
/>Form submission
Use formId to connect the primary button to a form element. No onClick needed.
<form id="my-form" onSubmit={handleSubmit}>
{/* form fields */}
</form>
<PropertyPanelFooter
secondaryAction={{ label: 'Cancel', onClick: handleCancel }}
primaryAction={{ label: 'Submit', formId: 'my-form' }}
/>Custom icons
Override default icons (trash for delete, floppy disk for primary) with custom ones.
import { faArrowRotateLeft, faCheck } from '@fortawesome/duotone-regular-svg-icons';
<PropertyPanelFooter
secondaryAction={{ label: 'Reset', onClick: handleReset, icon: faArrowRotateLeft }}
primaryAction={{ label: 'Apply', onClick: handleApply, icon: faCheck }}
/>FooterAction Props
| Prop | Type | Description |
|---|---|---|
label | string | Button text (required) |
onClick | () => void | Click handler (not needed if using formId) |
icon | IconDefinition | FontAwesome icon (defaults: trash/floppy disk) |
loading | boolean | Show loading spinner |
disabled | boolean | Disable the button |
formId | string | Form ID for submit (primaryAction only) |
Sub-components
For container mode or custom layouts, use these building blocks directly.
| Component | Purpose |
|---|---|
PropertyPanelHeader | Panel title and description area |
PropertyPanelContent | Scrollable content wrapper with padding |
PropertyPanelSection | Grouped fields with optional title |
PropertyPanelFooter | Sticky footer with action button props |
Props
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | - | Panel title text |
description | string | - | Panel description text |
children | ReactNode | - | Panel content |
footer | ReactNode | - | Footer content for actions |
size | 'normal' | 'wide' | 'wide' | Panel width variant |
emptyState | { title, description?, icon? } | - | Empty state configuration |
isEmpty | boolean | false | Whether to show empty state |
className | string | - | Additional CSS classes |