Skip to main content

EventGrid

Implemented

Responsive event grid — 1/2/3/4 columns at sm/md/lg/xl, capped at 48 events per grid. Same shape across all event listing pages. Loading branch renders an accessible skeleton grid (role='list' + aria-busy); empty branch composes the EmptyState molecule instead of hand-rolled markup. Composes the EventCard organism per item (single layout, no variant switch — Wave-3 L8c audit). Locale-aware via the `locale` prop (EN default, FR opt-in); 'fr' also merges the canonical EVENTCARD_LABELS_FR bag under each card's own `labels` (card-level keys win per key).

Categoryorganisms
Sourcecomponents/organisms/eventgrid/EventGrid.tsx
AI HintRaw responsive multi-column event grid — distinct from EventList (vertical 1-per-row, more metadata), EventsRow (horizontal scroll-snap rail, 240px cards) and FeaturedEvents (section wrapper with heading + 'View all', which accepts an EventGrid as `children`). Owns column counts and list semantics, but NOT the surrounding section chrome — pick FeaturedEvents when you want the homepage/events section chrome. Locale defaults to 'en' (unlike EventList/EventsRow which default to 'fr') so an unpropped `<EventGrid events={...} />` is byte-identical to the pre-i18n output. EventGrid itself authors only two strings (list aria-label + default empty title); everything else (event data, card labels) is call-site-owned.

Responsive multi-column grid of public EventCards. Column counts are configurable per breakpoint (1–4); the loading branch renders an accessible skeleton grid (aria-busy), and the empty branch composes the EmptyState molecule. Locale-aware: `locale="fr"` localizes the grid-authored strings and merges the canonical `EVENTCARD_LABELS_FR` bag under each card.

When to use

EventGrid is the raw responsive grid — it owns column counts and list semantics, but not the surrounding section chrome. Pair it with the sibling organisms depending on the layout you need:

  • EventGrid — responsive multi-column grid of EventCards (this component). Use when you need full control over column counts per breakpoint.
  • EventList — vertical 1-per-row list with more metadata per item (date, venue, city, price, CTA). Better for narrow viewports and search results.
  • EventsRow — horizontal scroll-snap row of 240px cards. Use for "also happening" strips inside a page section.
  • FeaturedEvents — section wrapper (heading + "View all" link + responsive padding) that takes an <EventGrid> as children. Use for the homepage / events listing chrome.

Usage

import { EventGrid } from '@epasslive/design-system'

// Default (en) — 1/2/3/4 columns at sm/md/lg/xl
<EventGrid events={events} />

// Custom columns + French locale
<EventGrid
  events={events}
  columns={{ sm: 1, md: 2, lg: 3 }}
  locale="fr"
/>

// Loading skeleton
<EventGrid events={[]} isLoading skeletonCount={8} />

Props

Prop
Type
Default
Description
events*
EventCardPublicConfig[]
—

Event cards to render. Rendered count is capped at 48 (`events.slice(0, 48)`); pass an empty array to render the empty state.

columns
{ sm?: 1 | 2 | 3 | 4; md?: 1 | 2 | 3 | 4; lg?: 1 | 2 | 3 | 4; xl?: 1 | 2 | 3 | 4 }
{ sm: 1, md: 2, lg: 3, xl: 4 }

Column count per breakpoint. Merged over the default — set only the breakpoints you want to override.

emptyState
EmptyStateConfig (deprecated)
—

Custom empty-state copy `{ title, message?, action? }`, rendered via the EmptyState molecule (`title→title`, `message→description`, `action→action`). Deprecated — compose the EmptyState molecule directly where you control the render.

isLoading
boolean
false

When true, renders an accessible skeleton grid (`role="list"` + `aria-busy="true"`) instead of events.

skeletonCount
number
6

Number of skeleton placeholders while loading; clamped to 1–12.

locale
"en" | "fr"
en

Locale for the strings EventGrid itself authors: list `aria-label` ("Events" / « Événements ») and the default empty title ("No events found" / « Aucun événement trouvé »). `"fr"` also merges the canonical `EVENTCARD_LABELS_FR` bag under each card's own `labels` (card-level keys win per key). Event data (`title`/`venue`/`priceLabel`) stays call-site-owned. Defaults to `en` — unlike EventList/EventsRow, which default to `fr`.

Props

Preview

EventGrid

Prop
Type
Required
Default
Description
events
EventCardPublicConfig[]
Required
—

Event cards to render. Rendered count is capped at 48 (`events.slice(0, 48)`); pass an empty array to render the empty state.

columns
{ sm?: 1 | 2 | 3 | 4; md?: 1 | 2 | 3 | 4; lg?: 1 | 2 | 3 | 4; xl?: 1 | 2 | 3 | 4 }
Optional
{ sm: 1, md: 2, lg: 3, xl: 4 }

Column count per breakpoint. Merged over the default — set only the breakpoints you want to override.

emptyState
EmptyStateConfig
Optional
—

Custom empty-state copy `{ title, message?, action? }`, rendered via the EmptyState molecule (`title→title`, `message→description`, `action→action`). The `EmptyStateConfig` interface is `@deprecated` — compose the EmptyState molecule directly instead; the prop is retained for backwards compatibility with EventGrid.

isLoading
boolean
Optional
false

When true, renders an accessible skeleton grid (`role='list'` + `aria-busy='true'`) instead of events.

skeletonCount
number
Optional
6

Number of skeleton placeholders while loading; clamped to 1–12.

locale
"en" | "fr"
Optional
"en"

Locale for the strings EventGrid itself authors — list `aria-label` ('Events' / « Événements ») and the default empty title ('No events found' / « Aucun événement trouvé »). 'fr' also merges the canonical `EVENTCARD_LABELS_FR` bag under each card's own `labels` (card-level keys win per key). Event data (`title`/`venue`/`priceLabel`) stays call-site-owned. Defaults to 'en' — unlike EventList/EventsRow which default to 'fr'.

Quick use:<EventGrid />

Accessibility

ARIA rolelist

Type

1 rule

NASA Rule 2

events bounded 0-48 (NASA Rule 2)

ARIA

1 rule

WCAG 4.1.3

role='list' aria-label is locale-dependent ('Events' / « Événements »); loading state sets aria-busy='true'; empty branch composes EmptyState (role='status')

Usage

Import

tsxSnippet
import { EventGrid } from "@epasslive/design-system"

Example 1

tsxSnippet
<EventGrid events={cards} columns={{ sm: 1, md: 2, lg: 3 }} locale="fr" />

Example 2

tsxSnippet
<EventGrid events={cards} emptyState={{ title: "Aucun événement", message: "Revenez bientôt.", action: <Button>Voir tous les événements</Button> }} locale="fr" />

Example 3

tsxSnippet
<EventGrid events={[]} isLoading skeletonCount={8} />

Anti-patterns

— Do not fetch data directly in organisms — adapters own that (EventGridAdapter precedent).

— Do not pass locale expecting event data translation — locale only switches grid-authored strings and merges the FR card-label bag; format/translate event titles, venues and price labels at the call site.

— Do not reach for a `variant` prop — EventGrid ships one layout (Wave-3 L8c audit). Use EventList (vertical) or EventsRow (horizontal rail) for the other layouts.

Design System v4.1.0 | ePassLive