ExpandableText

PreviousNext

A text container that truncates to a configurable number of lines and expands with a toggle button

Nestled between the Mediterranean Sea and the mountains, our resort offers an unforgettable all-inclusive experience. Enjoy world-class cuisine, daily activities, and breathtaking views every morning. Our dedicated G.Os are here to ensure every moment of your stay is filled with joy and discovery. From water sports to evening shows, there is something for every member of the family. Book now and create memories that last a lifetime.

'use client';
import { ExpandableText } from '@/ui/ExpandableText';

export function ExpandableTextDemo() {
  return (
    <div className="max-w-prose space-y-12">
      <ExpandableText
        id="desc"
        labels={{ expand: 'Read more', reduce: 'Show less' }}
        lineClamps="line-clamp-3"
      >
        <p>
          Nestled between the Mediterranean Sea and the mountains, our resort offers an
          unforgettable all-inclusive experience. Enjoy world-class cuisine, daily activities, and
          breathtaking views every morning. Our dedicated G.Os are here to ensure every moment of
          your stay is filled with joy and discovery. From water sports to evening shows, there is
          something for every member of the family. Book now and create memories that last a
          lifetime.
        </p>
      </ExpandableText>
    </div>
  );
}

Installation

npx shadcn@latest add https://develop.trident-ui.pro.clubmed/r/expandable-text.json

Usage

import { ExpandableText } from '@/ui/ExpandableText';
 
export function Component() {
  return (
    <ExpandableText
      id="product-description"
      labels={{ expand: 'Read more', reduce: 'Show less' }}
      lineClamps="line-clamp-3"
    >
      <p>Your long text content here…</p>
    </ExpandableText>
  );
}

API Reference

ExpandableText

PropTypeDefaultDescription
idstring—Required. ID applied to the inner content wrapper (used by aria-controls).
labelsExpandableTextLabels—Required. Object with expand and reduce strings for the toggle button.
lineClampsstring"line-clamp-3"A Tailwind line-clamp-* class used to truncate the content when collapsed.
buttonClassNamestringundefinedAdditional classes for the toggle button.
classNamestringundefinedAdditional classes for the outer height-animated container.
childrenReactNodeundefinedThe content to display. Renders nothing when absent.

ExpandableTextLabels

FieldTypeDescription
expandstringLabel for the button when collapsed.
reducestringLabel for the button when expanded.

Notes

  • Uses ResizeObserver internally to detect when the content overflows — the toggle button only appears when the text actually overflows the clamped height
  • Height transition is animated via a CSS --height custom property
  • The component renders nothing when children is falsy
  • The toggle button uses aria-controls pointing to the id prop and aria-expanded to communicate state
  • Works correctly with SSR: height CSS only applies on the client (useIsClient guard)