DetailPanel
Side panel component for displaying read-only detail information
DetailPanel
The DetailPanel component displays read-only field values in a side panel layout. It's commonly used to show detailed information about a selected item without leaving the main view.
Type Signature
interface DetailPanelProps {
/** Panel title */
title?: string
/** Panel description */
description?: string
/** Detail fields */
fields: Array<{
label: string
value: any
type?: string
format?: (value: any) => string
}>
/** Layout arrangement */
layout?: 'single' | 'two-column' | 'grid'
/** Show field labels */
showLabels?: boolean
/** Panel className */
className?: string
/** Collapsible panel */
collapsible?: boolean
/** Start collapsed */
defaultCollapsed?: boolean
}Usage
<DetailPanel
title="User Details"
description="View user information"
fields={[
{ label: 'Name', value: 'John Doe' },
{ label: 'Email', value: 'john@example.com' },
{ label: 'Role', value: 'Admin' },
{ label: 'Status', value: 'Active' },
{ label: 'Created', value: '2024-01-15', type: 'date' },
]}
/>Props
title
The panel title displayed in the header.
<DetailPanel title="Project Details" fields={fields} />description
Optional panel description or subtitle.
<DetailPanel
title="API Key"
description="View API key configuration and usage"
fields={fields}
/>fields
Array of field definitions to display. Each field has a label, value, optional type, and custom formatter.
<DetailPanel
fields={[
{
label: 'Name',
value: 'Acme Project',
},
{
label: 'Created',
value: '2024-01-15T10:30:00Z',
type: 'date',
format: (val) => new Date(val).toLocaleDateString(),
},
{
label: 'Budget',
value: 50000,
type: 'currency',
format: (val) => `$${val.toLocaleString()}`,
},
{
label: 'Active',
value: true,
type: 'boolean',
},
]}
/>layout
Field layout arrangement. Defaults to 'single'.
// Single column (default)
<DetailPanel layout="single" fields={fields} />
// Two columns
<DetailPanel layout="two-column" fields={fields} />
// Grid layout
<DetailPanel layout="grid" fields={fields} />showLabels
Controls whether field labels are displayed. Defaults to true.
<DetailPanel
showLabels={false}
fields={fields}
/>collapsible
Makes the panel collapsible with expand/collapse controls.
<DetailPanel
collapsible={true}
defaultCollapsed={false}
fields={fields}
/>Common Patterns
User Profile Details
<DetailPanel
title="Profile"
fields={[
{ label: 'Full Name', value: user.name },
{ label: 'Email', value: user.email },
{ label: 'Phone', value: user.phone },
{ label: 'Location', value: user.location },
{ label: 'Timezone', value: user.timezone },
{ label: 'Member Since', value: user.createdAt, type: 'date' },
]}
/>API Key Details
<DetailPanel
title="API Key Details"
description="Key configuration and usage information"
fields={[
{ label: 'Key Name', value: apiKey.name },
{ label: 'Key ID', value: apiKey.id },
{
label: 'Created',
value: apiKey.createdAt,
format: (val) => new Date(val).toLocaleDateString(),
},
{ label: 'Last Used', value: apiKey.lastUsedAt, type: 'date' },
{ label: 'Requests', value: apiKey.requestCount },
{ label: 'Rate Limit', value: `${apiKey.rateLimit}/hour` },
{ label: 'Status', value: apiKey.enabled ? 'Active' : 'Disabled' },
]}
/>Project Information
<DetailPanel
title="Project Info"
layout="two-column"
fields={[
{ label: 'Name', value: project.name },
{ label: 'Description', value: project.description },
{ label: 'Owner', value: project.owner.name },
{ label: 'Team', value: project.team.name },
{ label: 'Status', value: project.status },
{ label: 'Priority', value: project.priority },
{
label: 'Budget',
value: project.budget,
format: (val) => `$${val.toLocaleString()}`,
},
{ label: 'Start Date', value: project.startDate, type: 'date' },
{ label: 'End Date', value: project.endDate, type: 'date' },
{
label: 'Progress',
value: project.progress,
format: (val) => `${val}%`,
},
]}
/>Transaction Details
<DetailPanel
title="Transaction"
fields={[
{ label: 'ID', value: transaction.id },
{ label: 'Type', value: transaction.type },
{
label: 'Amount',
value: transaction.amount,
format: (val) => `$${(val / 100).toFixed(2)}`,
},
{ label: 'Status', value: transaction.status },
{ label: 'Customer', value: transaction.customer.name },
{ label: 'Payment Method', value: transaction.paymentMethod },
{ label: 'Date', value: transaction.createdAt, type: 'date' },
{ label: 'Invoice', value: transaction.invoiceId },
]}
/>Field Types and Formatting
Built-in Types
The panel recognizes common field types:
<DetailPanel
fields={[
{ label: 'Text', value: 'Hello World', type: 'string' },
{ label: 'Number', value: 42, type: 'number' },
{ label: 'Date', value: '2024-01-15', type: 'date' },
{ label: 'Boolean', value: true, type: 'boolean' },
{ label: 'Currency', value: 5000, type: 'currency' },
]}
/>Custom Formatters
Use the format function for custom value display:
<DetailPanel
fields={[
{
label: 'Duration',
value: 3600,
format: (seconds) => {
const hours = Math.floor(seconds / 3600)
const minutes = Math.floor((seconds % 3600) / 60)
return `${hours}h ${minutes}m`
},
},
{
label: 'File Size',
value: 1536000,
format: (bytes) => {
const mb = (bytes / 1024 / 1024).toFixed(2)
return `${mb} MB`
},
},
{
label: 'Percentage',
value: 0.7532,
format: (val) => `${(val * 100).toFixed(2)}%`,
},
]}
/>Layout Examples
Single Column
Default layout with full-width fields:
┌──────────────────────┐
│ Name: John Doe │
│ Email: john@... │
│ Role: Admin │
│ Status: Active │
└──────────────────────┘<DetailPanel layout="single" fields={fields} />Two Column
Fields arranged in two columns:
┌────────────────────────────┐
│ Name: John Role: Admin│
│ Email: john@...Status: │
│ .com Active │
└────────────────────────────┘<DetailPanel layout="two-column" fields={fields} />Grid Layout
Responsive grid with multiple columns:
<DetailPanel
layout="grid"
fields={[
{ label: 'Field 1', value: 'Value 1' },
{ label: 'Field 2', value: 'Value 2' },
{ label: 'Field 3', value: 'Value 3' },
{ label: 'Field 4', value: 'Value 4' },
{ label: 'Field 5', value: 'Value 5' },
{ label: 'Field 6', value: 'Value 6' },
]}
/>Panel Context Usage
DetailPanel can be used in different contexts:
Side Panel (Slideover)
Display details in a slideover panel:
<Shell>
<DashboardView>
<ItemList onSelect={(item) => setSelectedItem(item)} />
</DashboardView>
{selectedItem && (
<Slideover open={!!selectedItem} onClose={() => setSelectedItem(null)}>
<DetailPanel
title={selectedItem.name}
fields={[
{ label: 'ID', value: selectedItem.id },
{ label: 'Status', value: selectedItem.status },
{ label: 'Created', value: selectedItem.createdAt, type: 'date' },
]}
/>
</Slideover>
)}
</Shell>Inline Panel
Embedded within a page layout:
<div className="grid grid-cols-3 gap-4">
<div className="col-span-2">
<MainContent />
</div>
<div className="col-span-1">
<DetailPanel
title="Details"
collapsible={true}
fields={fields}
/>
</div>
</div>Modal Dialog
Show details in a modal:
<Dialog open={showDetails} onClose={() => setShowDetails(false)}>
<DetailPanel
title="Full Details"
layout="two-column"
fields={fields}
/>
</Dialog>Collapsible Panels
Make panels collapsible to save space:
<DetailPanel
title="Additional Information"
collapsible={true}
defaultCollapsed={true}
fields={[
{ label: 'Created By', value: 'John Doe' },
{ label: 'Modified By', value: 'Jane Smith' },
{ label: 'Created At', value: createdAt, type: 'date' },
{ label: 'Modified At', value: modifiedAt, type: 'date' },
]}
/>Empty States
Handle cases with no data:
<DetailPanel
title="Details"
fields={data.length > 0 ? data : [
{ label: 'No data', value: 'Select an item to view details' }
]}
/>Accessibility
DetailPanel implements accessibility best practices:
- Semantic HTML - Uses definition lists (
<dl>,<dt>,<dd>) - ARIA labels - Descriptive labels for screen readers
- Keyboard navigation - Collapsible panels keyboard accessible
- Focus management - Proper focus handling for interactive elements
<aside role="complementary" aria-labelledby="detail-panel-title">
<h2 id="detail-panel-title">User Details</h2>
<dl>
<dt>Name</dt>
<dd>John Doe</dd>
<dt>Email</dt>
<dd>john@example.com</dd>
</dl>
</aside>Best Practices
Group Related Fields
Organize fields into logical groups:
<div className="space-y-4">
<DetailPanel
title="Basic Information"
fields={basicFields}
/>
<DetailPanel
title="Contact Details"
fields={contactFields}
/>
<DetailPanel
title="Metadata"
collapsible={true}
defaultCollapsed={true}
fields={metadataFields}
/>
</div>Use Appropriate Layout
Choose layout based on field count and content:
// Few fields (< 5) - use single column
<DetailPanel layout="single" fields={shortList} />
// Many fields (5-10) - use two columns
<DetailPanel layout="two-column" fields={mediumList} />
// Lots of fields (> 10) - use grid
<DetailPanel layout="grid" fields={longList} />Format Values Consistently
Apply consistent formatting across your app:
const formatters = {
currency: (val) => `$${val.toLocaleString()}`,
date: (val) => new Date(val).toLocaleDateString(),
percentage: (val) => `${(val * 100).toFixed(1)}%`,
}
<DetailPanel
fields={[
{ label: 'Amount', value: 5000, format: formatters.currency },
{ label: 'Date', value: date, format: formatters.date },
{ label: 'Rate', value: 0.15, format: formatters.percentage },
]}
/>Related Components
- ActivityPanel - Activity feed component
- SearchBox - Modal search widget
- ChatBox - Slideover chat widget
- CommandPalette - Keyboard commands widget