Build / Organisms
EventHeaderCard
The top of an event: its picture, its name, and the two facts anyone actually needs — when, and where.
The cover is a backdrop rather than a picture. It is blurred and sunk under a scrim, because the job of a photo here is to say which event this is at a glance, and a legible name matters more than a sharp image. An event with no cover gets the brand under the same scrim, so a hero without a photo is a quieter hero rather than a broken one.
The scrim is dark in both light and dark mode — a photograph is not a
palette — so everything inside reads against a fixed on-color rather than
the page's. That is a token pair of its own (--deck-color-cover-*), and
the content layer re-points the solid-surface contract at it, which is
what makes Text, Heading, Badge and Button come out right in here
without any of them knowing they are on a photo.
The frame is a card, and holds the card rule: a fixed 1.75:1 box lying
down and 1:1.75 stood up, portrait on a phone and landscape from sm up.
The box never grows. The name clamps to three lines, the host's own title
drops out below sm, and if what is left still runs past the edge the
content scrolls inside the card rather than being cut off — this header
can hold an RSVP, and a control nobody can reach is worse than a scroll.
import { EventHeaderCard } from '@meetcard/deck'Example
<EventHeaderCard name="RevOps Summit" level={1} coverSrc={cover} badges={<Badge tone="success">Attending</Badge>} host={{ name: 'Hannah Davis', detail: 'Community Lead' }} facts={[{ icon: <CalendarDays />, title: 'Tuesday, May 18, 2027', detail: '9:00 AM – 4:30 PM' }]} />Stories
The whole thing: what you are to it, who runs it, when and where.
Source
const Default = () => <div style={{ maxWidth: 720 }}>
<EventHeaderCard
name="RevOps Summit"
coverSrc={'data:image/svg+xml;utf8,' +
encodeURIComponent(
/* Written with real `#`s: the whole string is encoded once on the way
into the data URI, so pre-escaping them here would encode the escape
and every fill would fall back to black. */
`<svg xmlns="http://www.w3.org/2000/svg" width="560" height="320">
<rect width="560" height="320" fill="#fdfbf7"/>
<circle cx="150" cy="90" r="130" fill="#ffe9c7"/>
<circle cx="430" cy="240" r="170" fill="#dbeee4"/>
<rect x="240" y="40" width="120" height="240" fill="#fff6e0"/>
</svg>`,
)}
level={1}
badges={(<>
<Badge tone="success" size="sm">
Attending
</Badge>
<Badge tone="warning" size="sm">
Soon
</Badge>
</>)}
host={{ name: 'Hannah Davis', detail: 'Community Lead, RevOps Collective' }}
facts={[
{
icon: <CalendarIcon />,
title: 'Tuesday, May 18, 2027',
detail: '9:00 AM – 4:30 PM',
},
{
icon: <PinIcon />,
title: 'Austin Convention Center',
detail: '500 E Cesar Chavez St, Austin, Texas',
},
]} />
</div>;Bare. Most events are entered in twenty seconds with no picture at all, so this is the common case rather than the fallback: the brand under the same scrim, and a hero that is quieter rather than broken.
Source
const WithoutACover = () => <div style={{ maxWidth: 720 }}>
<EventHeaderCard
name="RevOps Summit"
coverSrc={undefined}
level={1}
facts={[{ icon: <CalendarIcon />, title: 'Tuesday, May 18, 2027' }]} />
</div>;As a featured event on a list page: level={2}, a link on the name, and
whatever the page wants to hang underneath.
Source
const Featured = () => <div style={{ maxWidth: 720 }}>
<EventHeaderCard
name="RevOps Summit"
coverSrc={'data:image/svg+xml;utf8,' +
encodeURIComponent(
/* Written with real `#`s: the whole string is encoded once on the way
into the data URI, so pre-escaping them here would encode the escape
and every fill would fall back to black. */
`<svg xmlns="http://www.w3.org/2000/svg" width="560" height="320">
<rect width="560" height="320" fill="#fdfbf7"/>
<circle cx="150" cy="90" r="130" fill="#ffe9c7"/>
<circle cx="430" cy="240" r="170" fill="#dbeee4"/>
<rect x="240" y="40" width="120" height="240" fill="#fff6e0"/>
</svg>`,
)}
level={2}
href="/events/revops-summit"
badges={(<Badge tone="brand" size="sm">Happening next
</Badge>)}
facts={[
{ icon: <CalendarIcon />, title: 'Tuesday, May 18, 2027', detail: '9:00 AM' },
]}><Button size="sm">Add to calendar</Button></EventHeaderCard>
</div>;Phone. The header is a card, so it stands up here like every other card: a fixed 1:1.75 box. The host's own title drops out, the name clamps, and anything still too long scrolls inside the card rather than growing it.
Source
const Mobile = () => <EventHeaderCard
name="RevOps Summit"
coverSrc={'data:image/svg+xml;utf8,' +
encodeURIComponent(
/* Written with real `#`s: the whole string is encoded once on the way
into the data URI, so pre-escaping them here would encode the escape
and every fill would fall back to black. */
`<svg xmlns="http://www.w3.org/2000/svg" width="560" height="320">
<rect width="560" height="320" fill="#fdfbf7"/>
<circle cx="150" cy="90" r="130" fill="#ffe9c7"/>
<circle cx="430" cy="240" r="170" fill="#dbeee4"/>
<rect x="240" y="40" width="120" height="240" fill="#fff6e0"/>
</svg>`,
)}
level={1}
badges={<Badge tone="success" size="sm">Attending</Badge>}
host={{ name: 'Hannah Davis', detail: 'Community Lead, RevOps Collective' }}
facts={[
{ icon: <CalendarIcon />, title: 'Tuesday, May 18, 2027', detail: '9:00 AM – 4:30 PM' },
{ icon: <PinIcon />, title: 'Austin Convention Center' },
]} />;Props
| Prop | Type | Default | Description |
|---|---|---|---|
namerequired | string | — | — |
badges | ReactNode | — | Pills above the name: "Happening next", "Attending", "Soon". |
children | ReactNode | — | Anything below the facts — an RSVP, a share control, what's on next. |
coverSrc | string | — | The cover photo. Blurred behind a scrim — it is a backdrop, not an image. |
facts | EventHeaderCardFact[] | — | The facts of the thing: when, and where. |
host | EventHeaderCardHost | — | Who is putting it on. |
href | string | — | Makes the name a link to the event. |
level | 1 | 2 | 3 | 4 | 5 | 6 | 2 | Heading level for the name. 1 on the event's own page, 2 where the
event is one thing among others. The visual size follows from it — an
h1 is the page's subject and is sized like one. |
orientation | ResolvedCardOrientation | 'responsive' | — | Which way up the header sits. Default responsive: portrait on a phone,
landscape from sm up — the same rule as every other card. |
Also accepts everything from Omit, so id, data-* and event handlers pass straight through.