Collapse

Material Design 3-inspired expandable/collapsible component with smooth animations

Collapse

The Collapse component allows users to show and hide content sections with smooth animations. It’s perfect for FAQs, navigation menus, and content-heavy interfaces where space management is crucial.

Basic Usage

Basic Collapse

This is the collapsible content that can be shown or hidden.

States

Open State

Add collapse-open class to show the content:

Open State

This content is visible by default.

Closed State

Add collapse-closed class to hide the content:

Closed State

This content is hidden by default.

Variants

Bordered Variant

Add a border to the collapse component:

Bordered Variant

Content with a border around it.

Card Variant

Card variant with shadow and border:

Card Variant

This collapse has a card appearance with shadow.

Ghost Variant

Minimal styling for a clean look:

Ghost Variant

Minimal styling with transparent background.

Color Variants

Primary

Primary Color

Content with primary color theme.

Secondary

Secondary Color

Content with secondary color theme.

Tertiary

Tertiary Color

Content with tertiary color theme.

Sizes

Small

Small Size

Compact size for space-constrained layouts.

Medium (Default)

Medium Size (Default)

Standard size for most use cases.

Large

Large Size

Larger size for emphasis and better touch targets.

Accordion Groups

Create an accordion by grouping multiple collapse components:

Accordion Group

First section content is expanded by default.

Second section content is collapsed.

Third section content is collapsed.

Animation Variants

Fade Animation

Smooth fade in/out effect:

Fade Animation

Content fades in and out smoothly.

Slide Animation

Slide with transform effect:

Slide Animation

Content slides in from above with a transform.

Additional Features

With Divider

Add a divider between trigger and content:

With Divider

Content separated by a divider line.

Disabled State

Prevent interaction with the collapse:

Disabled State

This collapse cannot be toggled.

Loading State

Show a loading indicator:

Loading State

Content is being loaded...

Nested Collapse

Collapse components can be nested within each other:

Nested Collapse

Parent content with nested collapse below:

Nested collapse content with reduced padding.

JavaScript Integration

Add interactivity with JavaScript to toggle the collapse state:

JavaScript Integration

This content can be toggled with JavaScript.

Best Practices

Accessibility

  • Always use semantic <button> elements for triggers
  • Provide clear, descriptive labels
  • Ensure keyboard navigation support (Enter/Space to toggle)
  • Use ARIA attributes for better screen reader support

Accessible Collapse

Content with proper ARIA attributes.

Performance

  • Keep content lightweight for smooth animations
  • Avoid heavy computations during expand/collapse
  • Use CSS transforms for better performance
  • Consider lazy loading content for large datasets

UX Guidelines

  1. Clear Visual Feedback: Use icons to indicate expanded/collapsed state
  2. Smooth Animations: Default 300ms cubic-bezier provides good balance
  3. Touch Targets: Ensure triggers are at least 44×44px for mobile
  4. Context Preservation: Consider scroll position when toggling

Framework Examples

React

import { useState } from 'react';

interface CollapseProps {
  title: string;
  children: React.ReactNode;
  defaultOpen?: boolean;
  variant?: 'default' | 'bordered' | 'card' | 'ghost';
  color?: 'default' | 'primary' | 'secondary' | 'tertiary';
  size?: 'sm' | 'md' | 'lg';
}

export function Collapse({
  title,
  children,
  defaultOpen = false,
  variant = 'default',
  color = 'default',
  size = 'md'
}: CollapseProps) {
  const [isOpen, setIsOpen] = useState(defaultOpen);

  const classes = [
    'collapse',
    isOpen ? 'collapse-open' : 'collapse-closed',
    variant !== 'default' ? `collapse-${variant}` : '',
    color !== 'default' ? `collapse-${color}` : '',
    size !== 'md' ? `collapse-${size}` : ''
  ].filter(Boolean).join(' ');

  return (
    <div className={classes}>
      <button
        className="collapse-trigger"
        onClick={() => setIsOpen(!isOpen)}
        aria-expanded={isOpen}
      >
        <span>{title}</span>
        <span className="collapse-icon">▼</span>
      </button>
      <div className="collapse-content">
        {children}
      </div>
    </div>
  );
}

// Usage
<Collapse title="FAQ Item" variant="bordered" color="primary">
  <p>Answer to the frequently asked question.</p>
</Collapse>

Vue

<template>
  <div :class="collapseClasses">
    <button
      class="collapse-trigger"
      @click="toggle"
      :aria-expanded="isOpen"
    >
      <span>{{ title }}</span>
      <span class="collapse-icon">▼</span>
    </button>
    <div class="collapse-content">
      <slot />
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed } from 'vue';

interface Props {
  title: string;
  defaultOpen?: boolean;
  variant?: 'default' | 'bordered' | 'card' | 'ghost';
  color?: 'default' | 'primary' | 'secondary' | 'tertiary';
  size?: 'sm' | 'md' | 'lg';
}

const props = withDefaults(defineProps<Props>(), {
  defaultOpen: false,
  variant: 'default',
  color: 'default',
  size: 'md'
});

const isOpen = ref(props.defaultOpen);

const collapseClasses = computed(() => [
  'collapse',
  isOpen.value ? 'collapse-open' : 'collapse-closed',
  props.variant !== 'default' ? `collapse-${props.variant}` : '',
  props.color !== 'default' ? `collapse-${props.color}` : '',
  props.size !== 'md' ? `collapse-${props.size}` : ''
].filter(Boolean).join(' '));

const toggle = () => {
  isOpen.value = !isOpen.value;
};
</script>

<!-- Usage -->
<Collapse title="FAQ Item" variant="bordered" color="primary">
  <p>Answer to the frequently asked question.</p>
</Collapse>

Svelte

<script lang="ts">
  export let title: string;
  export let defaultOpen = false;
  export let variant: 'default' | 'bordered' | 'card' | 'ghost' = 'default';
  export let color: 'default' | 'primary' | 'secondary' | 'tertiary' = 'default';
  export let size: 'sm' | 'md' | 'lg' = 'md';

  let isOpen = defaultOpen;

  $: collapseClasses = [
    'collapse',
    isOpen ? 'collapse-open' : 'collapse-closed',
    variant !== 'default' ? `collapse-${variant}` : '',
    color !== 'default' ? `collapse-${color}` : '',
    size !== 'md' ? `collapse-${size}` : ''
  ].filter(Boolean).join(' ');
</script>

<div class={collapseClasses}>
  <button
    class="collapse-trigger"
    on:click={() => isOpen = !isOpen}
    aria-expanded={isOpen}
  >
    <span>{title}</span>
    <span class="collapse-icon">▼</span>
  </button>
  <div class="collapse-content">
    <slot />
  </div>
</div>

<!-- Usage -->
<Collapse title="FAQ Item" variant="bordered" color="primary">
  <p>Answer to the frequently asked question.</p>
</Collapse>

API Reference

Class Names

ClassDescription
.collapseBase collapse container (required)
.collapse-openExpanded state - shows content
.collapse-closedCollapsed state - hides content
.collapse-triggerClickable trigger/header element
.collapse-iconIcon that rotates on toggle
.collapse-contentContent area that expands/collapses
.collapse-borderedAdds border around collapse
.collapse-cardCard style with shadow and border
.collapse-ghostMinimal styling, transparent background
.collapse-primaryPrimary color theme
.collapse-secondarySecondary color theme
.collapse-tertiaryTertiary color theme
.collapse-smSmall size variant
.collapse-lgLarge size variant
.collapse-groupContainer for accordion groups
.collapse-fadeFade animation effect
.collapse-slideSlide animation with transform
.collapse-dividerAdds divider between trigger and content
.collapse-disabledDisables interaction
.collapse-loadingShows loading spinner

Animation Details

The collapse component uses the following animation timing:

  • Duration: 300ms
  • Easing: cubic-bezier(0.4, 0, 0.2, 1) - Material Design standard easing
  • Icon Rotation: 180deg on expand
  • Fade Transition: Opacity changes over 200ms
  • Slide Transform: translateY(-10px) when collapsed

Combinations

Combine classes for customized appearance:

Combined Variants

Combined styling options.

Multiple variant combinations.

  • Accordion - Multiple collapse components working together
  • Card - Container component
  • List - List items with expandable content
  • Tabs - Alternative content organization

See Also