Skip to main content

CollapsibleLayout

The CollapsibleLayout component provides an advanced expandable/collapsible container for React applications. It offers comprehensive features including controlled and uncontrolled state management, multiple animation styles, localStorage persistence, and complete accessibility support.

Features

  • Dual State Management - Both controlled and uncontrolled usage patterns
  • Multiple Animations - Fade, slide, and scale transitions with customizable duration
  • Flexible Triggers - Header click, button only, or both trigger areas
  • State Persistence - Optional localStorage integration to remember state
  • Visual Variants - Default, outlined, elevated, and filled styles
  • Customizable Spacing - Compact, comfortable, and spacious options
  • Rich Content Support - React nodes and HTML strings for all content areas
  • Complete Accessibility - WCAG 2.1 AA compliance with keyboard navigation
  • Data Binding - Full CMS integration through dataSource prop
  • Theme Integration - Material-UI theming and QwickApp framework support

Basic Usage

import { CollapsibleLayout } from '@qwickapps/react-framework';

function BasicExample() {
return (
<CollapsibleLayout
title="User Settings"
subtitle="Configure your account preferences"
defaultCollapsed={false}
>
<div>
<p>This content can be expanded or collapsed by clicking the header.</p>
<button>Save Settings</button>
</div>
</CollapsibleLayout>
);
}

State Management Patterns

Uncontrolled Component

For most use cases, use uncontrolled mode with defaultCollapsed:

function UncontrolledExample() {
const handleToggle = (collapsed) => {
console.log('Layout is now:', collapsed ? 'collapsed' : 'expanded');
};

return (
<CollapsibleLayout
title="Project Details"
subtitle="View project information and settings"
defaultCollapsed={true}
onToggle={handleToggle}
variant="outlined"
>
<div>
<h3>Project Configuration</h3>
<p>Detailed project settings and options...</p>
</div>
</CollapsibleLayout>
);
}

Controlled Component

For external state management, use controlled mode with collapsed:

import { useState } from 'react';

function ControlledExample() {
const [isCollapsed, setIsCollapsed] = useState(false);
const [showContent, setShowContent] = useState(true);

return (
<div>
<div style={{ marginBottom: '16px' }}>
<label>
<input
type="checkbox"
checked={showContent}
onChange={(e) => setShowContent(e.target.checked)}
/>
Show content
</label>
</div>

<CollapsibleLayout
title="Controlled Layout"
subtitle="State managed by external controls"
collapsed={!showContent}
onToggle={(collapsed) => setShowContent(!collapsed)}
variant="elevated"
>
<p>This layout's state is controlled by the checkbox above.</p>
</CollapsibleLayout>
</div>
);
}

Animation Options

Animation Styles

Choose from three built-in animation styles:

function AnimationExamples() {
return (
<div>
{/* Fade animation - smooth opacity transition */}
<CollapsibleLayout
title="Fade Animation"
animationStyle="fade"
animationDuration={300}
defaultCollapsed={true}
>
<p>Content fades in and out smoothly</p>
</CollapsibleLayout>

{/* Slide animation (default) - height-based transition */}
<CollapsibleLayout
title="Slide Animation"
animationStyle="slide"
animationDuration={300}
defaultCollapsed={true}
>
<p>Content slides up and down</p>
</CollapsibleLayout>

{/* Scale animation - combines scaling and fading */}
<CollapsibleLayout
title="Scale Animation"
animationStyle="scale"
animationDuration={200}
defaultCollapsed={true}
>
<p>Content scales and fades for dynamic effect</p>
</CollapsibleLayout>
</div>
);
}

Custom Animation Duration

function CustomDurationExample() {
return (
<div>
<CollapsibleLayout
title="Fast Animation (150ms)"
animationDuration={150}
defaultCollapsed={true}
>
<p>Quick, snappy transitions</p>
</CollapsibleLayout>

<CollapsibleLayout
title="Slow Animation (800ms)"
animationDuration={800}
defaultCollapsed={true}
>
<p>Deliberate, dramatic transitions</p>
</CollapsibleLayout>

{/* Disable animations entirely */}
<CollapsibleLayout
title="No Animation"
disableAnimations={true}
defaultCollapsed={true}
>
<p>Instant show/hide with no transition</p>
</CollapsibleLayout>
</div>
);
}

Visual Variants

Container Variants

function VariantExamples() {
return (
<div>
{/* Default - minimal styling */}
<CollapsibleLayout
title="Default Variant"
variant="default"
defaultCollapsed={false}
>
<p>Clean, minimal appearance</p>
</CollapsibleLayout>

{/* Outlined - subtle border */}
<CollapsibleLayout
title="Outlined Variant"
variant="outlined"
defaultCollapsed={false}
>
<p>Defined with border outline</p>
</CollapsibleLayout>

{/* Elevated - shadow effect */}
<CollapsibleLayout
title="Elevated Variant"
variant="elevated"
defaultCollapsed={false}
>
<p>Lifted appearance with shadow</p>
</CollapsibleLayout>

{/* Filled - background color */}
<CollapsibleLayout
title="Filled Variant"
variant="filled"
defaultCollapsed={false}
>
<p>Emphasized with background</p>
</CollapsibleLayout>
</div>
);
}

Spacing Options

function SpacingExamples() {
return (
<div>
{/* Compact - minimal padding */}
<CollapsibleLayout
title="Compact Layout"
headerSpacing="compact"
contentSpacing="compact"
variant="outlined"
>
<p>Dense layout for space-constrained interfaces</p>
</CollapsibleLayout>

{/* Comfortable (default) - balanced padding */}
<CollapsibleLayout
title="Comfortable Layout"
headerSpacing="comfortable"
contentSpacing="comfortable"
variant="outlined"
>
<p>Standard spacing for most applications</p>
</CollapsibleLayout>

{/* Spacious - generous padding */}
<CollapsibleLayout
title="Spacious Layout"
headerSpacing="spacious"
contentSpacing="spacious"
variant="outlined"
>
<p>Premium feel with generous whitespace</p>
</CollapsibleLayout>

{/* Mixed spacing */}
<CollapsibleLayout
title="Mixed Spacing"
subtitle="Compact header, spacious content"
headerSpacing="compact"
contentSpacing="spacious"
variant="outlined"
>
<p>Customize header and content spacing independently</p>
</CollapsibleLayout>
</div>
);
}

Advanced Content Features

Header Customization

import { Settings, Star, MoreVert } from '@mui/icons-material';

function HeaderCustomization() {
return (
<div>
{/* With lead icon and header actions */}
<CollapsibleLayout
title="User Profile Settings"
subtitle="Manage your account preferences"
leadIcon={<Settings color="primary" />}
headerActions={
<div style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>
<span style={{
fontSize: '12px',
backgroundColor: '#4caf50',
color: 'white',
padding: '2px 8px',
borderRadius: '12px'
}}>
Pro
</span>
<button>Edit</button>
<MoreVert />
</div>
}
>
<div>
<input type="text" placeholder="Display Name" />
<input type="email" placeholder="Email Address" />
<textarea placeholder="Bio"></textarea>
</div>
</CollapsibleLayout>
</div>
);
}

Collapsed Preview Content

function CollapsedPreviewExample() {
return (
<CollapsibleLayout
title="Article Preview"
subtitle="Click to read the full article"
defaultCollapsed={true}
variant="outlined"
collapsedView={
<div style={{
padding: '12px',
backgroundColor: '#f5f5f5',
borderRadius: '4px',
color: '#666'
}}>
📖 This article covers advanced React patterns and best practices
for building scalable applications. Click to expand and read more...
</div>
}
>
<div>
<h3>Advanced React Patterns</h3>
<p>
React has evolved significantly over the years, and with it, the patterns
and practices that help developers build maintainable, scalable applications.
In this comprehensive guide, we'll explore some of the most powerful advanced patterns.
</p>
<h4>1. Compound Components</h4>
<p>
Compound components provide a flexible and intuitive API for components that
need to work together...
</p>
<button>Read More</button>
</div>
</CollapsibleLayout>
);
}
function FooterContentExample() {
return (
<CollapsibleLayout
title="Project Status"
subtitle="Development progress and information"
defaultCollapsed={false}
footerView={
<div style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
paddingTop: '8px',
borderTop: '1px solid #eee',
marginTop: '16px'
}}>
<small style={{ color: '#666' }}>
Last updated: 2 hours ago
</small>
<button>View Details</button>
</div>
}
>
<div>
<div style={{ marginBottom: '16px' }}>
<strong>Development: Complete ✅</strong>
</div>
<div style={{ marginBottom: '16px' }}>
<strong>Testing: In Progress ⚠️</strong>
</div>
<div style={{
height: '8px',
backgroundColor: '#e0e0e0',
borderRadius: '4px',
overflow: 'hidden'
}}>
<div style={{
height: '100%',
width: '75%',
backgroundColor: '#4caf50',
borderRadius: '4px'
}}></div>
</div>
<small style={{ color: '#666' }}>Project is 75% complete</small>
</div>
</CollapsibleLayout>
);
}

Interaction Patterns

Trigger Areas

Control how users can expand/collapse the layout:

function TriggerAreaExamples() {
return (
<div>
{/* Header trigger - click anywhere on header */}
<CollapsibleLayout
title="Header Trigger"
subtitle="Click anywhere on the header"
triggerArea="header"
variant="outlined"
>
<p>Header area is clickable, no separate button</p>
</CollapsibleLayout>

{/* Button trigger - only the button works */}
<CollapsibleLayout
title="Button Trigger"
subtitle="Only the button toggles content"
triggerArea="button"
variant="outlined"
>
<p>Only the toggle button expands/collapses this</p>
</CollapsibleLayout>

{/* Both triggers - header or button */}
<CollapsibleLayout
title="Both Triggers"
subtitle="Header or button can toggle"
triggerArea="both"
variant="outlined"
>
<p>You can click the header OR use the toggle button</p>
</CollapsibleLayout>
</div>
);
}

Custom Icons

import { ArrowDropDown, ArrowDropUp, ExpandMore, ExpandLess } from '@mui/icons-material';

function CustomIconExamples() {
return (
<div>
{/* Material-UI icons */}
<CollapsibleLayout
title="Custom Material Icons"
collapsedIcon={<ArrowDropDown />}
expandedIcon={<ArrowDropUp />}
defaultCollapsed={false}
>
<p>Using ArrowDropDown and ArrowDropUp icons</p>
</CollapsibleLayout>

{/* Emoji icons */}
<CollapsibleLayout
title="Emoji Icons"
collapsedIcon="▶️"
expandedIcon="🔽"
defaultCollapsed={false}
>
<p>Using emoji as toggle icons</p>
</CollapsibleLayout>

{/* HTML string icons */}
<CollapsibleLayout
title="HTML Icons"
collapsedIcon='<span style="color: #4caf50;">+</span>'
expandedIcon='<span style="color: #f44336;">−</span>'
defaultCollapsed={false}
>
<p>Using HTML strings for custom styled icons</p>
</CollapsibleLayout>
</div>
);
}

State Persistence

localStorage Integration

function PersistentStateExample() {
return (
<div>
<p style={{
backgroundColor: '#e3f2fd',
padding: '12px',
borderRadius: '4px',
marginBottom: '16px'
}}>
💡 Try collapsing the sections below and refreshing the page -
the states will be remembered!
</p>

<CollapsibleLayout
title="Persistent Settings"
subtitle="This state is saved automatically"
defaultCollapsed={false}
persistState={true}
storageKey="user-settings-section"
variant="elevated"
>
<div>
<label>
<input type="checkbox" /> Enable notifications
</label>
<br />
<label>
<input type="checkbox" /> Auto-save changes
</label>
<br />
<button>Save Settings</button>
</div>
</CollapsibleLayout>

<CollapsibleLayout
title="Persistent Preferences"
subtitle="Another independently persisted section"
defaultCollapsed={true}
persistState={true}
storageKey="user-preferences-section"
variant="elevated"
>
<div>
<select>
<option>Light Theme</option>
<option>Dark Theme</option>
<option>Auto</option>
</select>
<br />
<input type="range" min="0" max="100" defaultValue="50" />
<br />
<button>Apply Preferences</button>
</div>
</CollapsibleLayout>
</div>
);
}

Data Binding Support

CMS Integration

import { QwickApp, CollapsibleLayout } from '@qwickapps/react-framework';
import { JsonDataProvider } from '@qwickapps/schema';

// Sample CMS data structure
const cmsData = {
'collapsible-sections': {
'faq-section': {
title: 'Frequently Asked Questions',
subtitle: 'Common questions and answers',
defaultCollapsed: false,
variant: 'outlined',
animationStyle: 'fade',
persistState: true,
storageKey: 'faq-section-state'
},
'help-section': {
title: 'Help & Support',
subtitle: 'Get assistance and documentation',
defaultCollapsed: true,
variant: 'elevated',
leadIcon: '❓',
collapsedView: '<p style="color: #666;"><em>Click to expand help resources...</em></p>'
}
}
};

function DataBindingExample() {
const dataProvider = new JsonDataProvider({ data: cmsData });

return (
<QwickApp
appId="collapsible-demo"
appName="Data Binding Demo"
dataSource={{ dataProvider }}
>
{/* FAQ section driven by CMS data */}
<CollapsibleLayout dataSource="collapsible-sections.faq-section">
<div>
<h3>How do I install the framework?</h3>
<p>Run `npm install @qwickapps/react-framework` in your project.</p>

<h3>Is TypeScript supported?</h3>
<p>Yes, full TypeScript support is included with complete type definitions.</p>

<h3>Can I customize the styling?</h3>
<p>Absolutely! Use the sx prop, CSS custom properties, or extend components.</p>
</div>
</CollapsibleLayout>

{/* Help section driven by CMS data */}
<CollapsibleLayout dataSource="collapsible-sections.help-section">
<div>
<ul>
<li><a href="/docs">📖 Documentation</a></li>
<li><a href="/examples">💡 Examples</a></li>
<li><a href="/support">🎧 Support</a></li>
<li><a href="/community">👥 Community</a></li>
</ul>
</div>
</CollapsibleLayout>
</QwickApp>
);
}

Props API Reference

CollapsibleLayout Component

PropTypeDefaultDescription
collapsedboolean-Controlled collapsed state (use for controlled mode)
defaultCollapsedbooleanfalseInitial collapsed state (uncontrolled mode)
onToggle(collapsed: boolean) => void-Callback when collapsed state changes
titlestring-Header title text
subtitlestring-Header subtitle text
leadIconReactNode | string-Icon displayed before title
headerActionsReactNode | string-Actions/controls in header area
collapsedViewReactNode | string-Content shown when collapsed
childrenReactNode | string-Main content shown when expanded
footerViewReactNode | string-Always visible footer content
triggerArea'header' | 'button' | 'both''both'Clickable area for toggling
animationStyle'fade' | 'slide' | 'scale''slide'Animation type for transitions
animationDurationnumber300Animation duration in milliseconds
disableAnimationsbooleanfalseDisable all animations
persistStatebooleanfalseSave state to localStorage
storageKeystring-Custom localStorage key
collapsedIconReactNode | string-Custom icon when collapsed
expandedIconReactNode | string-Custom icon when expanded
variant'default' | 'outlined' | 'elevated' | 'filled''default'Visual container style
headerSpacing'compact' | 'comfortable' | 'spacious''comfortable'Header padding amount
contentSpacing'compact' | 'comfortable' | 'spacious''comfortable'Content padding amount
showDividerbooleantrueShow divider between sections
toggleAriaLabelstring'Toggle content visibility'ARIA label for toggle button
aria-describedbystring-ID of element describing content
contentAriaPropsobject-Additional ARIA props for content
containerClassNamestring-CSS class for container
headerClassNamestring-CSS class for header
contentClassNamestring-CSS class for content
footerClassNamestring-CSS class for footer
dataSourcestring-CMS data source path
bindingOptionsobject-Data binding configuration
sxSxProps-Material-UI style overrides

useCollapsibleState Hook

Custom hook for managing collapsible state:

import { useCollapsibleState } from '@qwickapps/react-framework';

function CustomCollapsibleComponent() {
const { collapsed, toggle, setCollapsed, isControlled } = useCollapsibleState(
false, // controlled
undefined, // collapsedProp
false, // defaultCollapsed
undefined, // onToggle
true, // persistState
'my-section' // storageKey
);

return (
<div>
<button onClick={toggle}>
{collapsed ? 'Expand' : 'Collapse'}
</button>

{!collapsed && (
<div>Content is visible</div>
)}
</div>
);
}

Accessibility Features

WCAG 2.1 AA Compliance

The CollapsibleLayout component includes comprehensive accessibility features:

ARIA Support

  • role="button" on clickable header areas
  • aria-expanded indicates current state
  • aria-controls connects trigger to content
  • aria-describedby for additional context
  • role="region" on content area with proper labeling

Keyboard Navigation

  • Tab - Navigate to toggle controls
  • Enter - Expand/collapse content
  • Space - Alternative activation key
  • Escape - Optional collapse (when focused)

Screen Reader Support

  • Announces state changes ("expanded" / "collapsed")
  • Identifies interactive elements clearly
  • Provides context for content relationships
  • Supports high contrast mode

Testing Accessibility

function AccessibilityExample() {
return (
<CollapsibleLayout
title="Accessible Section"
subtitle="Fully keyboard navigable and screen reader friendly"
toggleAriaLabel="Toggle section visibility"
aria-describedby="section-help"
contentAriaProps={{
'aria-label': 'Section content',
role: 'region'
}}
>
<div>
<p>This content is accessible to all users.</p>
<button>Focusable Element</button>
</div>

<div id="section-help" style={{ display: 'none' }}>
Additional context for screen readers
</div>
</CollapsibleLayout>
);
}

Real-World Examples

Settings Dashboard

function SettingsDashboard() {
return (
<div>
<h1>User Settings</h1>

<CollapsibleLayout
title="Account Settings"
subtitle="Profile information and security"
leadIcon="👤"
defaultCollapsed={false}
variant="outlined"
persistState={true}
storageKey="account-settings"
>
<div style={{ display: 'grid', gap: '16px' }}>
<div>
<label>Display Name</label>
<input type="text" defaultValue="John Doe" style={{ width: '100%' }} />
</div>
<div>
<label>Email Address</label>
<input type="email" defaultValue="john@example.com" style={{ width: '100%' }} />
</div>
<div>
<label>
<input type="checkbox" defaultChecked />
Enable email notifications
</label>
</div>
<button>Save Changes</button>
</div>
</CollapsibleLayout>

<CollapsibleLayout
title="Privacy Settings"
subtitle="Control data usage and visibility"
leadIcon="🔒"
defaultCollapsed={true}
variant="outlined"
persistState={true}
storageKey="privacy-settings"
>
<div style={{ display: 'grid', gap: '12px' }}>
<label>
<input type="checkbox" defaultChecked />
Make profile public
</label>
<label>
<input type="checkbox" />
Show online status
</label>
<label>
<input type="checkbox" defaultChecked />
Allow friend requests
</label>
</div>
</CollapsibleLayout>

<CollapsibleLayout
title="Advanced Settings"
subtitle="Developer and system options"
leadIcon="⚙️"
defaultCollapsed={true}
variant="outlined"
headerActions={
<span style={{
fontSize: '11px',
backgroundColor: '#ff9800',
color: 'white',
padding: '2px 6px',
borderRadius: '8px'
}}>
Expert
</span>
}
collapsedView={
<p style={{ color: '#666', fontStyle: 'italic' }}>
⚠️ Advanced settings - for experienced users only
</p>
}
>
<div style={{
backgroundColor: '#fff3cd',
border: '1px solid #ffeaa7',
padding: '12px',
borderRadius: '4px',
marginBottom: '16px'
}}>
⚠️ These settings may affect application behavior
</div>

<div style={{ display: 'grid', gap: '12px' }}>
<label>
<input type="checkbox" />
Enable debug mode
</label>
<label>
<input type="checkbox" />
Beta features
</label>
<div>
<label>API Endpoint</label>
<input
type="url"
defaultValue="https://api.example.com"
style={{ width: '100%' }}
/>
</div>
</div>
</CollapsibleLayout>
</div>
);
}

FAQ Section

function FAQSection() {
const faqs = [
{
question: "How do I install QwickApps React Framework?",
answer: `Install using npm or yarn:

\`\`\`bash
npm install @qwickapps/react-framework
# or
yarn add @qwickapps/react-framework
\`\`\`

Then import components in your React application:

\`\`\`tsx
import { QwickApp, Button } from '@qwickapps/react-framework';
\`\`\``
},
{
question: "Does it support TypeScript?",
answer: "Yes! QwickApps React Framework is built with TypeScript and includes complete type definitions. You'll get full IntelliSense support and type safety out of the box."
},
{
question: "Can I customize the component styling?",
answer: `Absolutely! You have several options for customization:

• **sx prop** - Material-UI style overrides
• **CSS custom properties** - Global style variables
• **className prop** - Custom CSS classes
• **Component extension** - Create your own variants

The framework is designed to be highly customizable while maintaining consistency.`
}
];

return (
<div>
<h1>Frequently Asked Questions</h1>
<p>Find answers to common questions about QwickApps React Framework.</p>

{faqs.map((faq, index) => (
<CollapsibleLayout
key={index}
title={faq.question}
subtitle="Click to view answer"
defaultCollapsed={true}
variant="outlined"
animationStyle="fade"
triggerArea="both"
style={{ marginBottom: '12px' }}
>
<div style={{
backgroundColor: '#f8f9fa',
padding: '16px',
borderRadius: '4px',
whiteSpace: 'pre-wrap'
}}>
{faq.answer}
</div>
</CollapsibleLayout>
))}
</div>
);
}

Data Table with Expandable Details

function UserManagementTable() {
const users = [
{
id: 1,
name: 'John Doe',
email: 'john@example.com',
role: 'Admin',
status: 'Active',
details: {
lastLogin: '2025-01-14 15:30',
loginCount: 245,
permissions: ['read', 'write', 'admin']
}
},
{
id: 2,
name: 'Jane Smith',
email: 'jane@example.com',
role: 'Editor',
status: 'Pending',
details: {
lastLogin: 'Never',
loginCount: 0,
permissions: ['read', 'write']
}
}
];

return (
<div>
<h1>User Management</h1>

<div style={{ display: 'grid', gap: '8px' }}>
{users.map(user => (
<CollapsibleLayout
key={user.id}
title={
<div style={{ display: 'flex', alignItems: 'center', gap: '16px', flex: 1 }}>
<strong>{user.name}</strong>
<span style={{ color: '#666' }}>{user.email}</span>
<span style={{
fontSize: '12px',
padding: '2px 8px',
borderRadius: '12px',
backgroundColor: user.status === 'Active' ? '#4caf50' : '#ff9800',
color: 'white'
}}>
{user.status}
</span>
</div>
}
subtitle={`Role: ${user.role}`}
defaultCollapsed={true}
variant="outlined"
headerActions={
<div style={{ display: 'flex', gap: '8px' }}>
<button>Edit</button>
<button style={{ color: '#f44336' }}>Delete</button>
</div>
}
triggerArea="header"
>
<div style={{
display: 'grid',
gridTemplateColumns: '1fr 1fr',
gap: '16px',
padding: '16px',
backgroundColor: '#f8f9fa',
borderRadius: '4px'
}}>
<div>
<h4>Account Details</h4>
<p><strong>User ID:</strong> {user.id}</p>
<p><strong>Last Login:</strong> {user.details.lastLogin}</p>
<p><strong>Login Count:</strong> {user.details.loginCount}</p>
</div>

<div>
<h4>Permissions</h4>
<div style={{ display: 'flex', gap: '4px', flexWrap: 'wrap' }}>
{user.details.permissions.map(permission => (
<span key={permission} style={{
fontSize: '12px',
padding: '2px 6px',
backgroundColor: '#2196f3',
color: 'white',
borderRadius: '4px'
}}>
{permission}
</span>
))}
</div>
</div>
</div>
</CollapsibleLayout>
))}
</div>
</div>
);
}

Best Practices

1. Choose the Right State Pattern

// ✅ Good: Use uncontrolled for independent sections
<CollapsibleLayout defaultCollapsed={false} onToggle={handleToggle} />

// ✅ Good: Use controlled when external state management is needed
<CollapsibleLayout collapsed={externalState} onToggle={setExternalState} />

// ❌ Avoid: Mixing controlled and uncontrolled patterns
<CollapsibleLayout collapsed={state} defaultCollapsed={true} />

2. Provide Meaningful Content Preview

// ✅ Good: Informative collapsed view
<CollapsibleLayout
collapsedView="📊 View 5 charts and 12 metrics..."
/>

// ❌ Avoid: Generic or empty collapsed view
<CollapsibleLayout
collapsedView="Click to expand"
/>

3. Use Appropriate Animation Duration

// ✅ Good: Fast for frequent interactions
<CollapsibleLayout animationDuration={150} /> // FAQ items

// ✅ Good: Standard for most cases
<CollapsibleLayout animationDuration={300} /> // Settings sections

// ✅ Good: Slow for dramatic reveals
<CollapsibleLayout animationDuration={600} /> // Feature reveals

4. Consider Accessibility

// ✅ Good: Descriptive labels and ARIA support
<CollapsibleLayout
title="User Settings"
toggleAriaLabel="Toggle user settings section"
aria-describedby="settings-help"
/>

// ✅ Good: Keyboard-friendly trigger areas
<CollapsibleLayout triggerArea="both" /> // Header + button

5. Use State Persistence Wisely

// ✅ Good: Persist important sections
<CollapsibleLayout
persistState={true}
storageKey="user-settings-advanced"
/>

// ❌ Avoid: Generic storage keys (causes conflicts)
<CollapsibleLayout
persistState={true}
storageKey="section"
/>

Integration with Other QwickApps Components

With FormBlock

function RegistrationForm() {
return (
<CollapsibleLayout
title="Account Registration"
subtitle="Create your new account"
defaultCollapsed={false}
variant="elevated"
>
<FormBlock
fields={[
{ type: 'text', name: 'firstName', label: 'First Name', required: true },
{ type: 'text', name: 'lastName', label: 'Last Name', required: true },
{ type: 'email', name: 'email', label: 'Email Address', required: true },
{ type: 'password', name: 'password', label: 'Password', required: true }
]}
onSubmit={(data) => console.log('Registration:', data)}
submitLabel="Create Account"
/>
</CollapsibleLayout>
);
}

With DataProvider

function DataDrivenLayout() {
return (
<QwickApp dataSource={{ dataProvider }}>
<CollapsibleLayout
dataSource="layouts.user-profile"
title="{{title}}"
subtitle="{{subtitle}}"
variant="{{variant}}"
defaultCollapsed="{{defaultCollapsed}}"
>
<Content dataSource="content.user-profile" />
</CollapsibleLayout>
</QwickApp>
);
}

Migration from Other Collapsible Components

From Material-UI Accordion

// Before: Material-UI Accordion
import { Accordion, AccordionSummary, AccordionDetails } from '@mui/material';

<Accordion expanded={!collapsed} onChange={handleChange}>
<AccordionSummary>
<Typography>Title</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography>Content</Typography>
</AccordionDetails>
</Accordion>

// After: QwickApps CollapsibleLayout
import { CollapsibleLayout } from '@qwickapps/react-framework';

<CollapsibleLayout
title="Title"
collapsed={collapsed}
onToggle={(collapsed) => setCollapsed(collapsed)}
>
Content
</CollapsibleLayout>

From Custom Implementation

// Before: Custom collapsible
function CustomCollapsible({ title, children, defaultOpen = false }) {
const [isOpen, setIsOpen] = useState(defaultOpen);

return (
<div className="custom-collapsible">
<div className="header" onClick={() => setIsOpen(!isOpen)}>
{title}
<span>{isOpen ? '▼' : '▶'}</span>
</div>
{isOpen && (
<div className="content">
{children}
</div>
)}
</div>
);
}

// After: QwickApps CollapsibleLayout
<CollapsibleLayout
title={title}
defaultCollapsed={!defaultOpen}
animationStyle="slide"
variant="outlined"
>
{children}
</CollapsibleLayout>

Troubleshooting

Common Issues

Animation Not Working

// ❌ Problem: Animations disabled globally
<CollapsibleLayout disableAnimations={true} />

// ✅ Solution: Remove or set to false
<CollapsibleLayout disableAnimations={false} />

State Not Persisting

// ❌ Problem: Missing storage key or not unique
<CollapsibleLayout persistState={true} />

// ✅ Solution: Provide unique storage key
<CollapsibleLayout
persistState={true}
storageKey="unique-section-identifier"
/>

Controlled State Not Updating

// ❌ Problem: Missing onToggle handler
<CollapsibleLayout collapsed={isCollapsed} />

// ✅ Solution: Provide onToggle callback
<CollapsibleLayout
collapsed={isCollapsed}
onToggle={setIsCollapsed}
/>

Icons Not Displaying

// ❌ Problem: Invalid icon format
<CollapsibleLayout collapsedIcon="invalid-icon" />

// ✅ Solution: Use React component or valid HTML
<CollapsibleLayout
collapsedIcon={<ExpandMoreIcon />}
// or
collapsedIcon="<i class='fa fa-chevron-down'></i>"
/>

Performance Optimization

// ✅ Optimize re-renders with useMemo for complex content
function OptimizedCollapsible({ data }) {
const content = useMemo(() => (
<ComplexDataVisualization data={data} />
), [data]);

return (
<CollapsibleLayout title="Data Analysis">
{content}
</CollapsibleLayout>
);
}

// ✅ Use React.memo for frequently re-rendered components
const MemoizedCollapsible = React.memo(CollapsibleLayout);

The CollapsibleLayout component provides a comprehensive solution for expandable content with extensive customization options, accessibility features, and seamless integration with the QwickApps ecosystem. It's perfect for settings panels, FAQ sections, data tables, and any interface requiring progressive disclosure of information.