Accordion
Groups related long content into sections shown one at a time.
import Accordion from "@kiwicom/orbit-components/lib/Accordion";
import AccordionSection from "@kiwicom/orbit-components/lib/AccordionSection";
import ButtonLink from "@kiwicom/orbit-components/lib/ButtonLink";
import Heading from "@kiwicom/orbit-components/lib/Heading";
import Seat from "@kiwicom/orbit-components/lib/Seat";
import Stack from "@kiwicom/orbit-components/lib/Stack";
import Text from "@kiwicom/orbit-components/lib/Text";
() => {
const [expandedSection, setExpandedSection] = React.useState("")
const [selectedOutboundSeat, setSelectedOutboundSeat] = React.useState("1A")
const [selectedInboundSeat, setSelectedInboundSeat] = React.useState("1A")
const seatType = (currentSeat, direction) => {
if (direction === "outbound") {
return selectedOutboundSeat === currentSeat ? "legroom" : "default"
}
return selectedInboundSeat === currentSeat ? "legroom" : "default"
}
const SeatButton = ({ currentSeat, direction }) => (
<ButtonLink
compact
onClick={() =>
direction === "outbound"
? setSelectedOutboundSeat(currentSeat)
: setSelectedInboundSeat(currentSeat)
}
>
<Seat type={seatType(currentSeat, direction)} />
</ButtonLink>
)
const SeatRow = ({ direction, rowNumber }) => (
<Stack direction="row" align="center">
<SeatButton direction={direction} currentSeat={`${rowNumber}A`} />
<SeatButton direction={direction} currentSeat={`${rowNumber}B`} />
<Text>{rowNumber}</Text>
<SeatButton direction={direction} currentSeat={`${rowNumber}C`} />
<SeatButton direction={direction} currentSeat={`${rowNumber}D`} />
</Stack>
)
const SeatMap = ({ direction }) => (
<Stack>
<Stack direction="row" align="center">
<Stack inline grow={false} align="center" direction="column">
<Text>A</Text>
<SeatButton direction={direction} currentSeat="1A" />
</Stack>
<Stack inline grow={false} align="center" direction="column">
<Text>B</Text>
<SeatButton direction={direction} currentSeat="1B" />
</Stack>
<Stack inline grow={false} align="center" direction="column">
<Text> </Text>
<Text> </Text>
<Text>1</Text>
</Stack>
<Stack inline grow={false} align="center" direction="column">
<Text>C</Text>
<SeatButton direction={direction} currentSeat="1C" />
</Stack>
<Stack inline grow={false} align="center" direction="column">
<Text>D</Text>
<SeatButton direction={direction} currentSeat="1D" />
</Stack>
</Stack>
<SeatRow direction={direction} rowNumber={2} />
<SeatRow direction={direction} rowNumber={3} />
<SeatRow direction={direction} rowNumber={4} />
<SeatRow direction={direction} rowNumber={5} />
<SeatRow direction={direction} rowNumber={6} />
<SeatRow direction={direction} rowNumber={7} />
</Stack>
)
return (
<Accordion
expandedSection={expandedSection}
onExpand={(id) => setExpandedSection(id)}
>
<AccordionSection
id="outbound"
header={
<Heading as="h3" type="title3">
Seating for Barcelona
<FlightDirect ariaLabel=" to " />
Boston
</Heading>
}
>
<SeatMap direction="outbound" />
</AccordionSection>
<AccordionSection
id="inbound"
header={
<Heading as="h3" type="title3">
Seating for Boston
<FlightDirect ariaLabel=" to " />
Barcelona
</Heading>
}
>
<SeatMap direction="inbound" />
</AccordionSection>
</Accordion>
)
}
When to use
- You have long sections of content with similar structure, such as seat maps for various parts of a trip.
- You want to show only one section at a time (to keep users from being overwhelmed using progressive disclosure).
When not to use
- You want to display all content on the screen at once—use a card.
- Each section has a single associated action—use a tile.
- The information to hide is simple and doesn’t have a repeating structure—use a collapse.
Content structure

Behavior
Make actions clear
Accordions make content appear an disappear on the screen. If you’re not careful, users may start feeling lost.
Offer clear, persistent actions that make it clear how to get from one section to the next. And how to get back anything that has disappeared.
import Accordion from "@kiwicom/orbit-components/lib/Accordion";
import AccordionSection from "@kiwicom/orbit-components/lib/AccordionSection";
import ButtonLink from "@kiwicom/orbit-components/lib/ButtonLink";
import Heading from "@kiwicom/orbit-components/lib/Heading";
import Seat from "@kiwicom/orbit-components/lib/Seat";
import Stack from "@kiwicom/orbit-components/lib/Stack";
import Text from "@kiwicom/orbit-components/lib/Text";
() => {
const [expandedSection, setExpandedSection] = React.useState("outbound")
const [selectedOutboundSeat, setSelectedOutboundSeat] = React.useState("1A")
const [selectedInboundSeat, setSelectedInboundSeat] = React.useState("1A")
const seatType = (currentSeat, direction) => {
if (direction === "outbound") {
return selectedOutboundSeat === currentSeat ? "legroom" : "default"
}
return selectedInboundSeat === currentSeat ? "legroom" : "default"
}
const SeatButton = ({ currentSeat, direction }) => (
<ButtonLink
compact
onClick={() =>
direction === "outbound"
? setSelectedOutboundSeat(currentSeat)
: setSelectedInboundSeat(currentSeat)
}
>
<Seat type={seatType(currentSeat, direction)} />
</ButtonLink>
)
const SeatRow = ({ direction, rowNumber }) => (
<Stack direction="row" align="center">
<SeatButton direction={direction} currentSeat={`${rowNumber}A`} />
<SeatButton direction={direction} currentSeat={`${rowNumber}B`} />
<Text>{rowNumber}</Text>
<SeatButton direction={direction} currentSeat={`${rowNumber}C`} />
<SeatButton direction={direction} currentSeat={`${rowNumber}D`} />
</Stack>
)
const SeatMap = ({ direction }) => (
<Stack>
<Stack direction="row" align="center">
<Stack inline grow={false} align="center" direction="column">
<Text>A</Text>
<SeatButton direction={direction} currentSeat="1A" />
</Stack>
<Stack inline grow={false} align="center" direction="column">
<Text>B</Text>
<SeatButton direction={direction} currentSeat="1B" />
</Stack>
<Stack inline grow={false} align="center" direction="column">
<Text> </Text>
<Text> </Text>
<Text>1</Text>
</Stack>
<Stack inline grow={false} align="center" direction="column">
<Text>C</Text>
<SeatButton direction={direction} currentSeat="1C" />
</Stack>
<Stack inline grow={false} align="center" direction="column">
<Text>D</Text>
<SeatButton direction={direction} currentSeat="1D" />
</Stack>
</Stack>
<SeatRow direction={direction} rowNumber={2} />
<SeatRow direction={direction} rowNumber={3} />
<SeatRow direction={direction} rowNumber={4} />
<SeatRow direction={direction} rowNumber={5} />
<SeatRow direction={direction} rowNumber={6} />
<SeatRow direction={direction} rowNumber={7} />
</Stack>
)
return (
<Accordion
expandedSection={expandedSection}
onExpand={(id) => setExpandedSection(id)}
>
<AccordionSection
footer={
<Stack justify="center">
<ButtonLink
type="primary"
onClick={() => setExpandedSection("inbound")}
>
Continue to next segment
</ButtonLink>
</Stack>
}
id="outbound"
header={
<Heading as="h3" type="title3">
Seating for Barcelona
<FlightDirect ariaLabel=" to " />
Boston
</Heading>
}
>
<SeatMap direction="outbound" />
</AccordionSection>
<AccordionSection
footer={
<Stack justify="center">
<ButtonLink
type="secondary"
onClick={() => setExpandedSection("outbound")}
>
Back to previous segment
</ButtonLink>
</Stack>
}
id="inbound"
header={
<Heading as="h3" type="title3">
Seating for Boston
<FlightDirect ariaLabel=" to " />
Barcelona
</Heading>
}
>
<SeatMap direction="inbound" />
</AccordionSection>
</Accordion>
)
}
Content
Use for similar content
Accordion sections aren’t visible all of the time. Users may experience navigating between them as switching context.
Keep users comfortable by offering similar content in each section. This helps users scan for what they need among all their options.
Offer concrete headings
Section headings offer context for what each section contains. Use specific nouns to make it clear what users can expect on opening the section.
Visual style
Maintain visual hierarchy
Accordions are open to any content you want to put into them. Make sure to use a consistent style of heading to keep the overall visual hierarchy.
Using different styles can create conflicting visual messages.