Presentation primitives for repository summaries, project metadata, and responsive project grids
Overview
ProjectCard and ProjectGrid render project summaries without
taking over your data pipeline. Use them when you already know which projects to show
and need a stable display contract for cards, badges, and grid layout.
ProjectCard renders the card, link, optional stars, languages, and topics.
ProjectGrid provides the semantic list and responsive grid wrapper.
Fetching, ranking, filtering, and limiting metadata remain consumer responsibilities.
Contracts
ProjectCard props
name: string — rendered as the card heading and linked title
description: string — rendered as plain text and line-clamped to two lines
url: string — validated before use in href
stars?: number — shown only when greater than zero
languages? — optional badge entries with a language name and optional color
topics?: string[] — optional tags rendered with a # prefix
ProjectGrid contract
ProjectGrid takes no props. It renders a semantic unordered list and
expects list items in the default slot.
The layout starts as a single column and switches to two columns at wider breakpoints.
A minimal example showing the required ProjectCard props only.
Consumer Responsibilities
Data and state
Fetch project data from your API, content collection, or Git provider.
Decide ranking, filtering, grouping, and fallback behavior outside the primitives.
Limit topics and languages before rendering if your product needs a tighter display budget.
Handle loading, empty, and error states around the grid.
Link behavior and accessibility
The card title opens in a new tab with rel="noopener noreferrer". Use a
descriptive name so the heading and link text remain meaningful in screen
readers, browser tabs, and copied link lists.
Keep ProjectGrid children wrapped in <li> elements so
the list structure stays semantic.
Security
URL validation
ProjectCard validates project URLs before rendering them into
href. Safe values include:
HTTP and HTTPS URLs such as https://example.com
Explicit relative URLs such as /projects/snurble, ./page, and ../page
Dangerous or malformed URLs, including javascript:, data:,
vbscript:, protocol-relative URLs, and obfuscated schemes with leading
whitespace or control characters, are replaced with #.
Consumers should still validate upstream data and prefer fully qualified external URLs.
Color validation
Language colors are validated before they are written into inline styles. Accepted
formats include:
Hex colors: #RGB, #RRGGBB, #RRGGBBAA
RGB and RGBA functions
HSL and HSLA functions
A limited set of common named colors
Invalid or suspicious strings are ignored so the badge still renders without unsafe
styling. Choose colors upstream when they add meaning; omit them when they do not.