---
title: ElasticHeight
description: A container component that smoothly animates height transitions based on its content, perfect for collapsible sections, accordions, and expandable UI elements
---

```tsx
'use client';

import { useState } from 'react';
import { ElasticHeight } from '@/ui/ElasticHeight';

export function ElasticHeightDemo() {
  const [isExpanded, setIsExpanded] = useState(false);

  return (
    <div className="w-full max-w-md space-y-4">
      <button
        onClick={() => setIsExpanded(!isExpanded)}
        className="rounded-md bg-ultramarine px-4 py-2 text-white hover:bg-blue-700"
      >
        {isExpanded ? 'Collapse' : 'Expand'}
      </button>
      <ElasticHeight isExpanded={isExpanded} className="border rounded-md" min={24}>
        <div className="p-4 space-y-2">
          <p className="font-semibold">Expandable Content</p>
          <p>
            This content smoothly animates when the container expands or collapses. The
            ElasticHeight component automatically adjusts to the height of its children.
          </p>
          <p>
            Perfect for accordions, collapsible sections, and any UI element that needs smooth
            height transitions.
          </p>
        </div>
      </ElasticHeight>
    </div>
  );
}
```

## Installation

Using the CLI:

```bash
npx shadcn@latest add https://develop.trident-ui.pro.clubmed/r/elastic-height.json
```

Or manually, copy the following code into `/ui/elastic-height.tsx`:

```tsx
import clsx from 'clsx';
import { type ComponentPropsWithoutRef, type FunctionComponent, useRef } from 'react';

interface ElasticHeightProps extends ComponentPropsWithoutRef<'div'> {
  innerClassName?: string;
  isExpanded?: boolean;
  min?: number;
}

export const ElasticHeight: FunctionComponent<ElasticHeightProps> = ({
  className,
  children,
  innerClassName,
  isExpanded = false,
  min = 0,
  ...attrs
}) => {
  const ref = useRef<HTMLDivElement>(null as any);

  return (
    <div
      {...attrs}
      className={clsx(
        'overflow-hidden transition-all duration-500 grid',
        'data-[expanded=true]:grid-rows-[1fr]',
        'data-[expanded=false]:grid-rows-[0fr]',
        className,
      )}
      data-expanded={isExpanded}
    >
      <div
        style={{ minHeight: min }}
        className={clsx('overflow-hidden', innerClassName)}
        ref={ref}
        {...(!isExpanded ? { inert: true } : {})}
      >
        {children}
      </div>
    </div>
  );
};
```

## Usage

```tsx showLineNumbers
'use client';

import { useState } from 'react';
import { ElasticHeight } from '@/docs/lib/ui/elastic-height';

export function Component() {
  const [isExpanded, setIsExpanded] = useState(false);

  return (
    <div>
      <button onClick={() => setIsExpanded(!isExpanded)}>Toggle</button>
      <ElasticHeight isExpanded={isExpanded}>
        <div className="p-4">
          <p>This content animates smoothly when expanded or collapsed.</p>
        </div>
      </ElasticHeight>
    </div>
  );
}
```

## API Reference

### ElasticHeight

| Prop             | Type      | Default     | Description                                                                                                                              |
| ---------------- | --------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `isExpanded`     | `boolean` | `false`     | Controls whether the container is expanded (showing full content height) or collapsed (showing minimum height)                           |
| `min`            | `number`  | `0`         | The minimum height in pixels when collapsed. Use `0` to fully hide content or a positive value to show partial content                   |
| `innerClassName` | `string`  | `undefined` | CSS classes applied to the inner wrapper div that contains the children. Use this to add padding, styling, or layout to the content area |
| `className`      | `string`  | `undefined` | CSS classes applied to the outer container. Includes `overflow-hidden` and `transition-all duration-500` by default                      |

Extends all standard HTML `div` attributes.

## Implementation Details

- The component uses **CSS Grid** with `grid-rows-[1fr]` (expanded) and `grid-rows-[0fr]` (collapsed) for smooth height animations
- No JavaScript height calculations required - the browser handles sizing automatically
- The height transition has a **500ms duration** (`duration-500`) with smooth easing for polished animations
- The outer container has `overflow-hidden` to clip content during the transition
- The component sets a `data-expanded` attribute on the outer container for styling and testing purposes
- The inner container respects the `min` prop via `minHeight` inline style
- Use `min={0}` (default) to completely hide content when collapsed, or set a positive value to show a preview

## Benefits of CSS Grid Approach

- **Performance**: No JavaScript calculations or ResizeObserver overhead
- **Simplicity**: Pure CSS solution with no imperative DOM manipulation
- **Reliability**: Works consistently across all browsers that support CSS Grid
- **Automatic sizing**: Content height adjusts naturally without manual measurement
