Default
import { PixelFeatureCard } from '@pxlkit/ui-kit';
export function Default() {
return (
<PixelFeatureCard
title="Realtime sync"
description="Push every keystroke to peers via WebSockets — under 50ms p95."
/>
);
}Feature highlight card with toned icon frame, optional badge, title, clamped description, and footer — renders as <article>, role="button", or <a href> with full-card click target.
import { PixelFeatureCard } from '@pxlkit/ui-kit';| Prop | Type | Default | Description |
|---|---|---|---|
icon | React.ReactNode | — | Icon in the toned frame. |
iconSize | 48 | 56 | 64 | 80 | 56 | Width of the icon frame, in px. |
badge | { label: string; tone?: ToneKey } | — | Badge above the icon: its label and tone (cyan by default). |
title (required) | string | — | The heading, clamped to two lines. |
description | string | — | Muted paragraph rendered under the title. |
descriptionLines | 2 | 3 | 4 | — | Apply line-clamp-N + min-h-[N lh] to the description. |
desc | string | — | Deprecated. Use description for consistency with PixelCard / PixelPricingCard. |
descLines | 2 | 3 | 4 | — | Deprecated. Use descriptionLines for consistency with PixelCard / PixelPricingCard. |
footer | React.ReactNode | — | Footer under the description. |
tone | 'neutral' | 'green' | 'cyan' | 'gold' | 'red' | 'purple' | 'pink' | 'neutral' | Tone of the icon frame. |
interactive | boolean | false | Hover lift and focus ring; without an href the card is a button: give it an onClick. |
href | string | — | When provided, the card renders as <a href> and accepts anchor-specific attributes via the spread. Nesting interactive children inside the card (e.g. PixelButton, PixelTextLink) is invalid HTML in this mode. |
target | '_self' | '_blank' | '_parent' | '_top' | (string & {}) | — | Anchor target — only meaningful when href is set. |
rel | string | — | Anchor rel — only meaningful when href is set. |
download | any | — | Anchor download — only meaningful when href is set. |
onClick | React.MouseEventHandler<HTMLElement> | — | When interactive=true without href, an onClick is REQUIRED for accessibility. |
orientation | 'vertical' | 'horizontal' | 'vertical' | Icon above the text, or beside it. |
surface | 'pixel' | 'linear' | — | Surface override; defaults to the nearest provider. |
bordered | boolean | true | Render with surface-aware border + radius chrome. Defaults to true — a feature card needs visible chrome. |
Also takes the native attributes and event handlers of its element (HTMLAttributes<HTMLElement>).
ref points to its element (HTMLElement).
WCAG target: 2.1 AA
buttonlinkSemantic <article> by default. When interactive without href, the root becomes <div role="button" tabindex="0"> with Enter/Space activation parity (<article> does not permit role="button"). When href is set, the root renders as a native <a> with the entire card as the click target — nesting interactive children (PixelButton, PixelTextLink) inside footer is invalid HTML in href mode and breaks screen reader navigation. Focus-visible ring is provided automatically in both interactive modes.
| Key | Action | When |
|---|---|---|
| Enter | Activates the card when interactive (role="button") or follows the link when href is set | — |
| Space | Activates the card when interactive (role="button") | interactive prop is true and href is not set |
| Tab | Moves focus to the card when interactive or anchored | — |
import { PixelFeatureCard } from '@pxlkit/ui-kit';
export function Default() {
return (
<PixelFeatureCard
title="Realtime sync"
description="Push every keystroke to peers via WebSockets — under 50ms p95."
/>
);
}import { PixelFeatureCard } from '@pxlkit/ui-kit';
export function Default() {
return (
<PixelFeatureCard
title="Realtime sync"
description="Push every keystroke to peers via WebSockets — under 50ms p95."
/>
);
}import { PixelFeatureCard } from '@pxlkit/ui-kit';
const PixelIcon = (
<svg viewBox="0 0 8 8" shapeRendering="crispEdges" fill="currentColor" className="h-4 w-4">
<rect x="3" y="0" width="2" height="8" />
<rect x="0" y="3" width="8" height="2" />
</svg>
);
export function WithIcon() {
return (
<PixelFeatureCard
icon={PixelIcon}
title="Pixel-perfect"
description="Crisp edges on every retina ratio thanks to shape-rendering: crispEdges."
/>
);
}import { PixelFeatureCard } from '@pxlkit/ui-kit';
const PixelIcon = (
<svg viewBox="0 0 8 8" shapeRendering="crispEdges" fill="currentColor" className="h-4 w-4">
<rect x="3" y="0" width="2" height="8" />
<rect x="0" y="3" width="8" height="2" />
</svg>
);
export function WithBadge() {
return (
<PixelFeatureCard
icon={PixelIcon}
badge={{ label: 'NEW', tone: 'gold' }}
title="AI Companion"
description="A built-in copilot that learns your codebase as you ship it."
/>
);
}import { PixelFeatureCard } from '@pxlkit/ui-kit';
const PixelIcon = (
<svg viewBox="0 0 8 8" shapeRendering="crispEdges" fill="currentColor" className="h-4 w-4">
<rect x="3" y="0" width="2" height="8" />
<rect x="0" y="3" width="8" height="2" />
</svg>
);
export function Tones() {
return (
<div className="grid grid-cols-2 gap-3">
<PixelFeatureCard icon={PixelIcon} tone="cyan" title="Cyan" description="Tinted icon frame." />
<PixelFeatureCard icon={PixelIcon} tone="green" title="Green" description="Tinted icon frame." />
<PixelFeatureCard icon={PixelIcon} tone="gold" title="Gold" description="Tinted icon frame." />
<PixelFeatureCard icon={PixelIcon} tone="purple" title="Purple" description="Tinted icon frame." />
</div>
);
}import { PixelFeatureCard } from '@pxlkit/ui-kit';
const PixelIcon = (
<svg viewBox="0 0 8 8" shapeRendering="crispEdges" fill="currentColor" className="h-4 w-4">
<rect x="3" y="0" width="2" height="8" />
<rect x="0" y="3" width="8" height="2" />
</svg>
);
export function Surfaces() {
return (
<div className="grid grid-cols-2 gap-3">
<PixelFeatureCard surface="pixel" icon={PixelIcon} title="Pixel" description="Thick border + offset shadow." />
<PixelFeatureCard surface="linear" icon={PixelIcon} title="Linear" description="Soft border + smooth radius." />
</div>
);
}import { PixelFeatureCard } from '@pxlkit/ui-kit';
const PixelIcon = (
<svg viewBox="0 0 8 8" shapeRendering="crispEdges" fill="currentColor" className="h-4 w-4">
<rect x="3" y="0" width="2" height="8" />
<rect x="0" y="3" width="8" height="2" />
</svg>
);
export function Horizontal() {
return (
<PixelFeatureCard
orientation="horizontal"
icon={PixelIcon}
title="Horizontal layout"
description="Icon sits to the left of the title and description."
/>
);
}import { PixelFeatureCard } from '@pxlkit/ui-kit';
const PixelIcon = (
<svg viewBox="0 0 8 8" shapeRendering="crispEdges" fill="currentColor" className="h-4 w-4">
<rect x="3" y="0" width="2" height="8" />
<rect x="0" y="3" width="8" height="2" />
</svg>
);
export function Interactive() {
return (
<PixelFeatureCard
interactive
onClick={() => alert('feature clicked')}
icon={PixelIcon}
title="Click me"
description="Press Enter or Space to activate via keyboard."
/>
);
}import { PixelFeatureCard } from '@pxlkit/ui-kit';
const PixelIcon = (
<svg viewBox="0 0 8 8" shapeRendering="crispEdges" fill="currentColor" className="h-4 w-4">
<rect x="3" y="0" width="2" height="8" />
<rect x="0" y="3" width="8" height="2" />
</svg>
);
export function AsLink() {
return (
<PixelFeatureCard
href="https://example.com"
target="_blank"
rel="noopener noreferrer"
icon={PixelIcon}
title="Read the docs"
description="Root renders as <a href> when href is provided."
/>
);
}import { PixelFeatureCard } from '@pxlkit/ui-kit';
const PixelIcon = (
<svg viewBox="0 0 8 8" shapeRendering="crispEdges" fill="currentColor" className="h-4 w-4">
<rect x="3" y="0" width="2" height="8" />
<rect x="0" y="3" width="8" height="2" />
</svg>
);
export function WithFooter() {
return (
<PixelFeatureCard
icon={PixelIcon}
title="Realtime sync"
description="Push every keystroke to peers via WebSockets."
footer={<span className="text-xs text-retro-muted">Learn more →</span>}
/>
);
}import { PixelFeatureCard } from '@pxlkit/ui-kit';
const PixelIcon = (
<svg viewBox="0 0 8 8" shapeRendering="crispEdges" fill="currentColor" className="h-4 w-4">
<rect x="3" y="0" width="2" height="8" />
<rect x="0" y="3" width="8" height="2" />
</svg>
);
export function ClampedDescription() {
return (
<PixelFeatureCard
icon={PixelIcon}
title="Long Description"
description="This description is intentionally long to demonstrate the line-clamp behavior. It will be truncated to the configured number of lines with an ellipsis, while maintaining a minimum height so cards stay aligned in a grid."
descriptionLines={2}
/>
);
}import { PixelFeatureCard } from '@pxlkit/ui-kit';
const PixelIcon = (
<svg viewBox="0 0 8 8" shapeRendering="crispEdges" fill="currentColor" className="h-4 w-4">
<rect x="3" y="0" width="2" height="8" />
<rect x="0" y="3" width="8" height="2" />
</svg>
);
export function IconSizes() {
return (
<div className="grid grid-cols-2 gap-3">
<PixelFeatureCard icon={PixelIcon} iconSize={48} title="Small" description="48px icon frame." />
<PixelFeatureCard icon={PixelIcon} iconSize={80} title="Large" description="80px icon frame." />
</div>
);
}