A card is a container that promises the things inside it belong together. That promise is easy to make and easy to break: the moment one card in a grid has a two-line title and another has five, or one has a badge and the next does not, the row stops reading as a set and starts reading as a mistake.
733 public components on 21st have "card" in the name, which puts it second only to buttons. Almost all of the variety is in the surface treatment. Almost all of the failures are in the content.
The plain one, which is most of them
Media, title, one or two lines of text, metadata, an action. That is the whole pattern, and it is what shadcn/ui's Card gives you as slots with no opinion about the inside.
The decisions worth making once, at the design-system level rather than per card:
Fix the media aspect ratio. One aspect-[4/3] with object-cover and a grid stops being ragged. Letting the image set its own height is the single most common cause of a broken card row.
Clamp the text. line-clamp-2 on the title and line-clamp-3 on the body, chosen once and applied everywhere. A card grid where every card is a different height is a card grid nobody scans.
Decide what happens with no image. Every catalogue eventually meets a record without one. A neutral block, an initial, a generated gradient - anything decided in advance beats a collapsed layout discovered in production.
The interactive one
Where the catalogue's energy goes: the card that reacts to the cursor.
Spotlight Card by Hossain Jahed is the most-bookmarked card on 21st and the pattern most products copy: a radial highlight that follows the pointer across the surface. Evervault Card by Manu Arora reveals encrypted text under a mixed gradient on hover, and Glare Card by the same author is the reflective-sheen version.
Gradient Card Showcase by Le Thanh and Glass Blog Card by Moumen Soliman are the material treatments of the same rectangle.
Two things to know before a grid of these ships. Pointer-tracking effects usually attach a mousemove listener per card, and thirty of them on one page is thirty listeners running on every frame; track on the container instead and pass the coordinates down. And none of them exist on touch, so the phone version has to be designed, not inherited.




The stack
When cards are a sequence rather than a set, depth beats a row. Display Cards by Codehagen is the stacked layout with hover animations and a grayscale treatment on the cards behind. Morphing Card Stack by Kousthubha Yadiyala and Cards Stack by youcefbnm are the animated takes, and ScannerCardStream by Rahil Vahora is the continuous-feed version.
This shape suits a hero, an onboarding step or a testimonial rotation. It suits a listing badly, because a reader scanning for one record needs to see them all at once, and depth hides everything but the front.
The one that expands
Expandable Card by Erik X is the pattern where the card opens into the detail rather than navigating away.
It is genuinely good for a gallery or a media grid where the detail is short. It is a trap for anything the reader might want to link to, because an expanded card has no URL: no sharing, no back button, no way for a search engine or an answer engine to reach the content inside. If the detail deserves an address, make it a page and let the card link to it.




Making a whole card clickable without breaking it
The most common piece of broken markup in any component library. A card that wraps everything in an <a> swallows the button inside it. A card with an onClick on the container is invisible to the keyboard and cannot be opened in a new tab.
The version that works is the stretched link: keep the container plain, put a real <a href> on the title, and let a pseudo-element on that link cover the card.
The title stays the accessible name, the whole rectangle is clickable, middle-click and open-in-new-tab work, and any real button inside just needs position: relative and a higher z-index to sit above the overlay. One caveat: text inside a stretched card is no longer selectable, so do not use it where the card body is something people copy.
What a card grid costs
Cards are cheap individually and expensive in bulk, and the two costs are images and effects.
Images are the bigger one. A grid of forty cards is forty network requests and forty decodes, and the fix is not a nicer loader: it is loading="lazy", correct width and height so nothing reflows, a sizes attribute so the browser fetches the right variant, and modern formats. A card grid that ships full-resolution JPEGs is the most common reason a listing page fails Core Web Vitals.
Effects are the smaller one until they compound. Shadow plus blur plus a gradient border plus a pointer-tracked highlight, times forty, is a compositing bill. Simplify the card in the grid and keep the full treatment for the one that is featured.
Where else to look
The honest list of alternatives, because the answer is not always us:
| Source | Best for | Trade-off |
|---|---|---|
| shadcn/ui | The slots: header, content, footer, with no opinion about the inside | It is a container; every pattern above is yours to build |
| Tailwind CSS | line-clamp, aspect-ratio and grid, which solve the real problems | Not components |
| Tailwind Plus | Conventional card grids with the responsive states already decided | Paid, and the look is shared with every other site using it |
| 21st | The treatments: spotlight, glare, stacks, expandables | Quality varies by author, so preview before you take it |
Taking one
Every component page has a live preview and the code. Installing goes through the shadcn CLI against our registry:
That key comes from your 21st account, and installs require a membership. Set API_KEY_21ST once in your shell and the command works for anything in the catalogue. The 21st MCP covers the same ground without leaving the editor: ask Claude, Cursor or Codex for a card, get the previews inline, and let the agent write the file.
Frequently asked
- How do you keep a card grid from looking ragged?
- Fix three things once at the design-system level rather than per card: a fixed media aspect ratio with object-cover, line-clamp on the title and body so every card is the same height, and a decided fallback for records with no image. Letting the image set its own height is the commonest cause of a broken row.
- How do you make an entire card clickable and still accessible?
- Use the stretched link. Keep the container plain, put a real anchor on the title, and let a pseudo-element on that link cover the card with position absolute and inset 0. The title stays the accessible name, the whole rectangle is clickable, and middle-click still works. Buttons inside need position relative and a higher z-index. The trade-off is that text in the card is no longer selectable.
- Why is my card listing slow?
- Images, almost always. Forty cards is forty requests and forty decodes. Use loading="lazy", set width and height so nothing reflows, add a sizes attribute so the browser fetches the right variant, and serve a modern format. Effects compound after that: shadow plus blur plus gradient border plus pointer tracking, times forty, is a real compositing bill.
- Should a card expand in place or link to a page?
- Expand for a gallery where the detail is short. Link when the detail deserves an address. An expanded card has no URL, which means no sharing, no back button, and nothing for a search engine or an answer engine to reach. Anything you would want cited needs to be a page.