Skip to main content

ExpansionPanel

The ExpansionPanel component provides a way to organize and hide content behind an expandable panel. It’s based on Material-UI’s Accordion component and works with several subcomponents for flexible layouts.

Installation

npm install @naturacosmeticos/natds-web

Usage

import {
  ExpansionPanel,
  ExpansionPanelSummary,
  ExpansionPanelDetails
} from '@naturacosmeticos/natds-web';

function BasicExpansionPanel() {
  return (
    <ExpansionPanel>
      <ExpansionPanelSummary>
        Panel Title
      </ExpansionPanelSummary>
      <ExpansionPanelDetails>
        Panel content goes here
      </ExpansionPanelDetails>
    </ExpansionPanel>
  );
}

Composition Pattern

ExpansionPanel requires specific child components to work properly:
<ExpansionPanel>
  <ExpansionPanelSummary>  {/* Header/Title */}
    Summary content
  </ExpansionPanelSummary>
  <ExpansionPanelDetails>  {/* Main content */}
    Details content
  </ExpansionPanelDetails>
  <ExpansionPanelActions>  {/* Optional actions */}
    Action buttons
  </ExpansionPanelActions>
</ExpansionPanel>

Variants

Basic Expansion Panel

Simple panel with text content:
<ExpansionPanel>
  <ExpansionPanelSummary>
    What is Natura?
  </ExpansionPanelSummary>
  <ExpansionPanelDetails>
    Natura is a Brazilian cosmetics company committed to sustainability
    and natural ingredients.
  </ExpansionPanelDetails>
</ExpansionPanel>

With Expand Icon

Add an icon to indicate expandable state:
import { Icon } from '@naturacosmeticos/natds-web';

<ExpansionPanel>
  <ExpansionPanelSummary
    expandIcon={<Icon name="outlined-navigation-arrowbottom" />}
  >
    Expandable Section
  </ExpansionPanelSummary>
  <ExpansionPanelDetails>
    Content revealed when expanded
  </ExpansionPanelDetails>
</ExpansionPanel>

With Actions

Add action buttons to the panel:
import { Button, Divider } from '@naturacosmeticos/natds-web';

<ExpansionPanel>
  <ExpansionPanelSummary>
    Confirm your action
  </ExpansionPanelSummary>
  <ExpansionPanelDetails>
    Are you sure you want to proceed with this action?
  </ExpansionPanelDetails>
  <Divider />
  <ExpansionPanelActions>
    <Button size="small">Cancel</Button>
    <Button size="small" color="primary">Confirm</Button>
  </ExpansionPanelActions>
</ExpansionPanel>

With Typography

Use Typography components for better text styling:
import { Typography } from '@naturacosmeticos/natds-web';

<ExpansionPanel>
  <ExpansionPanelSummary>
    <Typography variant="h6">Section Header</Typography>
  </ExpansionPanelSummary>
  <ExpansionPanelDetails>
    <div>
      <Typography variant="subtitle1" color="primary">
        Subtitle
      </Typography>
      <Typography variant="body2" color="textSecondary">
        Detailed content with proper typography styling.
      </Typography>
    </div>
  </ExpansionPanelDetails>
</ExpansionPanel>

Controlled ExpansionPanel

Manage expansion state externally:
function ControlledExpansionPanel() {
  const [expanded, setExpanded] = React.useState(false);

  const handleChange = (event, isExpanded) => {
    setExpanded(isExpanded);
  };

  return (
    <ExpansionPanel expanded={expanded} onChange={handleChange}>
      <ExpansionPanelSummary>
        Controlled Panel
      </ExpansionPanelSummary>
      <ExpansionPanelDetails>
        This panel's state is controlled by parent component
      </ExpansionPanelDetails>
    </ExpansionPanel>
  );
}

Multiple Panels

Create an accordion-style group where only one panel is open at a time:
function AccordionGroup() {
  const [expanded, setExpanded] = React.useState('panel1');

  const handleChange = (panel) => (event, isExpanded) => {
    setExpanded(isExpanded ? panel : false);
  };

  return (
    <div>
      <ExpansionPanel 
        expanded={expanded === 'panel1'} 
        onChange={handleChange('panel1')}
      >
        <ExpansionPanelSummary>
          Panel 1
        </ExpansionPanelSummary>
        <ExpansionPanelDetails>
          Content for panel 1
        </ExpansionPanelDetails>
      </ExpansionPanel>

      <ExpansionPanel 
        expanded={expanded === 'panel2'} 
        onChange={handleChange('panel2')}
      >
        <ExpansionPanelSummary>
          Panel 2
        </ExpansionPanelSummary>
        <ExpansionPanelDetails>
          Content for panel 2
        </ExpansionPanelDetails>
      </ExpansionPanel>

      <ExpansionPanel 
        expanded={expanded === 'panel3'} 
        onChange={handleChange('panel3')}
      >
        <ExpansionPanelSummary>
          Panel 3
        </ExpansionPanelSummary>
        <ExpansionPanelDetails>
          Content for panel 3
        </ExpansionPanelDetails>
      </ExpansionPanel>
    </div>
  );
}

Default Expanded

Start with a panel expanded:
<ExpansionPanel defaultExpanded>
  <ExpansionPanelSummary>
    Initially Expanded
  </ExpansionPanelSummary>
  <ExpansionPanelDetails>
    This panel is expanded by default
  </ExpansionPanelDetails>
</ExpansionPanel>

Disabled Panel

<ExpansionPanel disabled>
  <ExpansionPanelSummary>
    Disabled Panel
  </ExpansionPanelSummary>
  <ExpansionPanelDetails>
    This content cannot be accessed
  </ExpansionPanelDetails>
</ExpansionPanel>

Props

ExpansionPanel

children
node
required
The content of the expansion panel. Must be ExpansionPanelSummary, ExpansionPanelDetails, or ExpansionPanelActions components.
defaultExpanded
boolean
default:"false"
If true, expands the panel by default.
disabled
boolean
default:"false"
If true, the panel will be displayed in a disabled state.
expanded
boolean
If true, expands the panel, otherwise collapses it. Setting this prop enables control over the panel.
onChange
(event: object, expanded: boolean) => void
Callback fired when the expand/collapse state is changed.
TransitionComponent
element
The component used for the collapse effect. Defaults to Collapse.
TransitionProps
object
Props applied to the Transition element.

ExpansionPanelSummary

children
node
The content of the summary, typically a title or header.
expandIcon
node
The icon to display as the expand indicator.
IconButtonProps
object
Props applied to the IconButton element wrapping the expand icon.

ExpansionPanelDetails

children
node
The content to display when the panel is expanded.

ExpansionPanelActions

children
node
The action buttons to display, typically Button components.

Subcomponents

  • ExpansionPanelSummary: The header/title area that is always visible
  • ExpansionPanelDetails: The content area that expands/collapses
  • ExpansionPanelActions: Optional actions section for buttons

Important Notes

All children of ExpansionPanel must be ExpansionPanelActions, ExpansionPanelDetails, or ExpansionPanelSummary components. Otherwise, you may receive the error: TypeError: Cannot read property 'props' of undefined at Accordion

Best Practices

  • Use ExpansionPanelSummary for the title/header content
  • Place main content in ExpansionPanelDetails
  • Use ExpansionPanelActions for action buttons
  • Add expand icons to make the interaction clear
  • Consider using controlled expansion for complex interactions
  • Separate actions from details content with a Divider
  • Keep summary content concise and descriptive

Accessibility

  • The component automatically handles ARIA attributes
  • Expansion state is communicated to screen readers
  • Keyboard navigation is supported (Enter/Space to toggle)
  • Ensure expand icons have sufficient contrast
  • Provide meaningful summary text
  • Accordion - React package alternative
  • Collapse - For custom expand/collapse behavior
  • Button - For actions in ExpansionPanelActions
  • Icon - For expand indicators

Build docs developers (and LLMs) love