ValuePropsStrip
ImplementedHorizontal strip of 3-4 value proposition items with icon, heading, and description. Used in storefront landing pages to communicate trust signals (secure payment, instant delivery, etc.).
src/components/molecules/valuepropsstrip/ValuePropsStrip.tsxHorizontal strip of 3-4 value proposition items with icon, heading, and description.
ValuePropsStrip
Content & Layout — molecule
Icon-led marketing trust strip beneath heroes: bounded 3-4 items, region landmark with a required accessible name.
Secure payment
Encrypted checkout on every order.
Instant tickets
Scan-ready passes the moment you pay.
Mobile wallet
Tickets and receipts in one place.
Refund guarantee
Clear refunds on every purchase.
ValuePropsStrip — compact
Content & Layout — molecule
Compact variant: same responsive ladder, one-step smaller type scale (text-ep-xs), tighter rhythm (py-6/lg:py-8, gap-6/md:gap-8, 32px icon chip) for dense surfaces such as checkout panels.
Secure payment
Encrypted checkout on every order.
Instant tickets
Scan-ready passes the moment you pay.
Mobile wallet
Tickets and receipts in one place.
Usage
Data-in molecule: pass 3-4 typed items plus the required ariaLabel. Icons are Phosphor components imported per-icon from @phosphor-icons/react/dist/ssr (ADR-022) and render filled (weight="fill") on the teal chip.
import { ShieldCheck, Ticket, Wallet, Receipt } from "@phosphor-icons/react/dist/ssr";
import { ValuePropsStrip } from "@epasslive/design-system";
const valueProps = [
{ icon: ShieldCheck, heading: "Secure payment", description: "Encrypted checkout on every order." },
{ icon: Ticket, heading: "Instant tickets", description: "Scan-ready passes the moment you pay." },
{ icon: Wallet, heading: "Mobile wallet", description: "Tickets and receipts in one place." },
{ icon: Receipt, heading: "Refund guarantee", description: "Clear refunds on every purchase." },
];
// Default — 4 items beneath a hero
<ValuePropsStrip items={valueProps} ariaLabel="Why ePassLive" />
// Compact — 3 items on a dense surface
<ValuePropsStrip items={valueProps.slice(0, 3)} variant="compact" ariaLabel="Event benefits" />Bounds
items.length must be 3-4, enforced at runtime. In development the component throws Error("ValuePropsStrip: items.length must be 3-4, got N"); in production it logs console.warn("[ValuePropsStrip] items.length must be 3-4, got N — rendering nothing.") and renders nothing. Do not pass 2 items — the guard fires by design (a two-item caption is a Caption, not a ValuePropsStrip). No out-of-bounds example is rendered live here on purpose: it would throw in dev and take this page down.
Responsive
One breakpoint, two layouts — no intermediate tablet grid. Below md: stacked single column, icon left of text. At md and up: horizontal 3-4-up row, icon above text. The compact variant uses the same ladder with a one-step smaller type scale (text-ep-xs vs text-ep-sm), tighter padding, tighter gaps and a 32px icon chip.
Accessibility
- The root is a
role="region"landmark named by the requiredariaLabelprop. - Items render as a real
ul/lilist, so screen readers announce the item count. - Icons are decorative (
aria-hidden— thePhosphorIconatom default); the heading carries the meaning. - No
aria-liveby design — static content must not be a live region. - Contrast meets WCAG AA in both themes: heading
text-ep-text-headingand descriptiontext-ep-text-muted(5.49:1) onbg-ep-surface-card; icon glyphtext-ep-text-teal(5.70:1) onbg-ep-teal/10. - Items are non-interactive — no focus targets.
href/onItemClickare deliberately excluded from the API. - Reduced motion is respected: nothing animates by default.
Props
items*ValuePropsItem[]3-4 value props, runtime-guarded (see Bounds). Each item: { icon: PhosphorComponent; heading: string; description: string } — icon is the Phosphor component imported per-icon from @phosphor-icons/react/dist/ssr (ADR-022). Heading 2-4 words; description up to 140 chars.
variant"default" | "compact""default"default: horizontal strip at md+ (icon above text), stacked below md (icon left of text). compact: same ladder with a one-step smaller type scale (text-ep-xs vs text-ep-sm) and tighter rhythm — py-6/lg:py-8, gap-6/md:gap-8, 32px icon chip — for dense surfaces.
ariaLabel*stringAccessible name for the role="region" landmark. Required — unlike CardGrid, this strip is a named landmark. Examples: "Why ePassLive", "Event benefits".
classNamestringAdditional classes on the root element.
idstringStable root id; falls back to an SSR-safe useId() value.
Props
ValuePropsStrip
itemsArray<{ icon: PhosphorIconComponent; heading: string; description: string }>—3-4 value props (minItems=3, maxItems=4 per NASA Rule 2, runtime-guarded). Each item: icon (Phosphor component reference, per-icon import per ADR-022), heading, description.
variant'default' | 'compact''default''default' = 1-col stacked below md, 3-4-up row at md+. 'compact' = tighter gaps + smaller icon chip for dense surfaces.
ariaLabelstring—Required for region landmark. Examples: 'Why ePassLive' or 'Event benefits'.
classNamestring—Additional CSS classes for the root element.
idstring—Optional id for the root element.
<ValuePropsStrip />Accessibility
Type
1 ruleARIA
1 ruleUsage
Import
import { ValuePropsStrip } from "@epasslive/design-system"Example 1
<ValuePropsStrip ariaLabel="Why ePassLive" items={[{ icon: ShieldCheck, heading: "Secure payment", description: "..." }]} />Example 2
<ValuePropsStrip variant="compact" ariaLabel="Benefits" items={threeItems} />Anti-patterns
— Do not hardcode data in molecules
— Avoid complex business logic in molecules
— Do not add aria-live — the strip is static content
— Do not pass icon name strings — pass Phosphor component references (ADR-022 tree-shaking)