Deck
Browse the catalog

Build / Organisms

ShareSheet

  • organism
  • play-fn

The share dialog, wherever something can be shared.

One component rather than one per surface, because the product already treats it as one: a person's card, a company profile, a booking flow and an event all raise the same dialog, and three of those four call the thing being shared "this card". Only the noun and the link change, which is why subject is a noun slotted into a fixed sentence rather than a free title.

An organism, not a molecule: it wraps Sheet, which is itself an organism, and a molecule is a grouping of atoms. It composes Sheet + CopyField (molecule) + QRCode and two Buttons (atoms).

Inherits Sheet's placement, so it is a bottom sheet on a phone and a centred panel from 640px up — which is where you are when you are sharing a link, and where a thumb is when you are sharing a code.

The code carries the link as its accessible description, so someone who cannot scan still reaches the destination. showValue is off because the copy row beneath already prints it, and twice is noise.

import { ShareSheet } from '@meetcard/deck'

Example

<ShareSheet open={open} onClose={close} value="meetcard.io/ben@meetcard"> <SomeGeneratedSvg /> </ShareSheet>

Stories

Every preview below is the real component, rendered in this page from the same story Storybook runs. The width control resizes each preview's container; CSS media queries still follow the browser window, so breakpoint behaviour is worth checking in Storybook.

Sharing a person's card — the most common of the four surfaces.

Default
Source
const Default = () => <Harness
    open={false}
    onClose={fn()}
    value="meetcard.io/ben@meetcard"
    onDownloadQr={fn()}
    onShareLinkedIn={fn()}
    label="Share card"><Matrix /></Harness>;

An event — the only surface that changes the noun. A company profile and a booking flow both still say "card".

Event
Source
const Event = () => <Harness
    open={false}
    onClose={fn()}
    value="meetcard.io/events/boulder-startup-week-2026-05-04"
    onDownloadQr={fn()}
    onShareLinkedIn={fn()}
    subject="event"
    label="Share event"><Matrix /></Harness>;

Both actions are optional — with neither handled, the row is absent.

Link Only
Source
const LinkOnly = () => <Harness
    open={false}
    onClose={fn()}
    value="meetcard.io/ben@meetcard"
    onDownloadQr={undefined}
    onShareLinkedIn={undefined}
    label="Share card"><Matrix /></Harness>;

Props

PropTypeDefaultDescription
onCloserequired() => void——
openrequiredboolean——
valuerequiredstring—The short link — displayed, copied, and named in the code's accessible description, e.g. "meetcard.io/ben@meetcard".
childrenReactNode—An inline <svg> of the code, as an alternative to qrSrc. QRCode is presentational: it draws a plate around an image you supply and never generates one. Deck has no QR library and adding one would be the first runtime dependency in src/components. Generate the code upstream and pass it in.
onDownloadQr() => void—Omit to hide the download action.
onShareLinkedIn() => void—Omit to hide the LinkedIn action.
qrSrcstring—Rendered QR image. See the note on children — Deck encodes nothing.
subjectReactNode'card'The noun in "Share this …". Defaults to card, which is what a person's card, a company profile, and a booking flow all use — only an event says anything else. Passing a whole title instead would let the four surfaces drift apart, which is the thing this component exists to prevent.

Open in Storybookfor controls, the a11y panel and the interaction runner.