Copy clamped on a line boundary that unrolls from where you were reading.
Preview
npx shadcn add @fetaui/expandable-textThrown by hand in a small studio outside Porto, each cup is made from a coarse local stoneware that fires to a warm oatmeal tone. A satin glaze breaks over the iron speckles in the clay, so no two cups in a set are quite alike.
They hold 300 ml, which suits a flat white, a long black, or a generous pour of tea. The rim is rolled thin for drinking, the walls are thick enough to keep coffee warm, and the unglazed foot is sanded smooth so it will not scratch a table.
Dishwasher and microwave safe. Because every cup is made by hand, sizes can vary by a few millimetres and small marks from the kiln are part of the piece.
Thrown by hand in a small studio outside Porto, each cup is made from a coarse local stoneware that fires to a warm oatmeal tone. A satin glaze breaks over the iron speckles in the clay, so no two cups in a set are quite alike.
They hold 300 ml, which suits a flat white, a long black, or a generous pour of tea. The rim is rolled thin for drinking, the walls are thick enough to keep coffee warm, and the unglazed foot is sanded smooth so it will not scratch a table.
Dishwasher and microwave safe. Because every cup is made by hand, sizes can vary by a few millimetres and small marks from the kiln are part of the piece.
Thrown by hand in a small studio outside Porto, each cup is made from a coarse local stoneware that fires to a warm oatmeal tone. A satin glaze breaks over the iron speckles in the clay, so no two cups in a set are quite alike.
They hold 300 ml, which suits a flat white, a long black, or a generous pour of tea. The rim is rolled thin for drinking, the walls are thick enough to keep coffee warm, and the unglazed foot is sanded smooth so it will not scratch a table.
Dishwasher and microwave safe. Because every cup is made by hand, sizes can vary by a few millimetres and small marks from the kiln are part of the piece.
Installation
npx shadcn add @fetaui/expandable-text
Accessibility
- Every paragraph stays in the DOM, so screen readers read it all.
- Read more is labelled Show the full description.
Motion
- Height goes from three lines to full in 320 ms and keeps your place.
- With reduced motion, it jumps.
Responsive behavior
- 14 / 21 on Web and 15 / 22 on Mobile.
Performance
- Every paragraph stays in the DOM. A ResizeObserver re-measures, so the clamp holds on resize.
- The unroll uses the Web Animations API on height for 320 ms, then releases.
Note for AI
Give your coding assistant the Markdown reference instead of screenshots.
- Import ExpandableText. Pass one <p> per paragraph. Props: lines, defaultOpen, onOpenChange, moreLabel, lessLabel, moreAriaLabel.
- The toggle only appears when the copy runs past lines.
- It composes Button.