Load More
Clamps a long region to a couple of rows, fades its cut edge, and puts one reveal button under it. The fade is a mask, not a painted gradient, so it works unchanged on any surface.
Installation#
Usage#
import { LoadMore, LoadMoreContent, LoadMoreTrigger } from "@/components/ui/load-more"
export function Example() {
return (
<LoadMore>
<LoadMoreContent>{/* the long grid, list or stack */}</LoadMoreContent>
<LoadMoreTrigger more="See all" less="Show less" />
</LoadMore>
)
}Collapsed height#
collapsedHeight sets how much shows before the reveal. Pick a value that cuts through a row rather than landing between two: a clean break reads as the end of the list, which is the opposite of the message you want. The default is 28rem.
Alignment#
align moves the reveal button under the region: center (the default, which reads as a page-level affordance), start, or end. The button's row is always in flow, never floated over the fade, so opening costs no layout shift of its own.
Any surface#
The cut edge fades through the fade-b mask utility rather than a background-coloured gradient panel, so it needs to know nothing about what sits behind it. The same component on a solid brand band cuts correctly with no configuration, where a painted gradient would smear the page background across the accent. The band is deep and its ramp is eased, so the clamp trails off instead of ending on a line. With tone="onMedia" the trigger becomes the white chip: on a band it is the only action on the fill, so it takes the light shape.
Without the fade#
fade={false} keeps the region opaque to the last pixel. Reach for it when a soft edge would misread as "this text trails off": a legal notice, a price list, a data table.
Open by default#
defaultExpanded opens on mount, for a deep link that should land on the full list. The component owns the state from there on; pair it with onExpandedChange to react to each toggle.
API reference#
LoadMore forwards every div prop and adds collapsedHeight (any CSS length, default 28rem), defaultExpanded, onExpandedChange, and align. LoadMoreContent forwards every div prop and adds fade. LoadMoreTrigger forwards every Button prop and takes more and less for its two labels. Its variant defaults to outline, or to the solid chip under an onMedia or onInverse tone. It renders its own caret, which rotates to point wherever the region is about to move, so there is no icon to pass. Every part accepts className.