QuickBuyBar
PlannedSticky quick-buy bar at bottom of event page — event name, date, price from, and 'Buy Now' CTA. Appears on scroll past hero. Critical UX pattern: 3-click purchase flow.
patterns/molecules/quickbuybar.htmlSticky quick-buy bar at bottom of event page — event name, date, price from, and 'Buy Now' CTA. Appears on scroll past hero. Critical UX pattern: 3-click purchase flow.
QuickBuyBar
Commerce — Family 7 (planned)
Sticky quick-buy bar at the bottom of the event page: event name, date, a 'from' price and a Buy Now CTA that appears once the hero scrolls out of view.
Osheaga — Day 1
Sat Aug 1, 2026 · 14:00
from $89.50
Osheaga — Day 1
Sat Aug 1, 2026 · 14:00
from $89.50
Osheaga — Day 1
Sat Aug 1, 2026 · 14:00
from CA$89.50
Design reference mock — not a rendered component. The third row shows the planned TicketSelector composition (quantity stepper, barrel-exported organism) — not yet part of the canonical contract.
This component supports light and dark mode.
Status
Planned molecule — the React component is not yet implemented. Nothing is exported from the DS barrel; the render above is a design reference mock typed to the planned interface, not the component.
Composition targets (all barrel-exported, ready to compose): PriceTag (atom, variant="from-prefix", locale-aware Intl.NumberFormat) for the price display, Button (atom, size="lg", loading={isLoading}) for the Buy Now CTA, and TicketSelector (organism, value / onChange / min / max) for optional inline quantity selection. Do not use the Stepper molecule — it is a progress stepper (steps / currentIndex), not a quantity input.
Planned API
Sketch of the intended contract. Until the component ships, this is not importable code.
interface QuickBuyBarProps {
eventName: string;
eventDate: string;
priceFrom: number;
currency?: string; // 'USD' per patterns.ts — reconcile with PriceTag ('CAD')
onBuyNow: () => void;
isLoading?: boolean;
}
// Sketch — QuickBuyBar is planned and NOT exported from the barrel yet.
<QuickBuyBar
eventName="Osheaga — Day 1"
eventDate="Sat Aug 1, 2026 · 14:00"
priceFrom={89.5}
currency="CAD"
onBuyNow={() => router.push('/checkout')}
isLoading={false}
/>The implementation composes existing atoms: PriceTag with variant="from-prefix" renders the locale-aware "from" price, and Button with size="lg" loading={isLoading} renders the CTA (44×44px tap target and aria-busy come from the atom). For optional inline quantity, compose the barrel-exported TicketSelector organism (value / onChange / min / max) — the Stepper molecule is progress-only and cannot serve as a quantity input.
When to use
- Event detail pages, once the hero (with its own CTA) scrolls out of view.
- The 3-click purchase flow: page → bar CTA → ticket selection.
- Do not stack with another sticky bar (cookie / App banners) — reserve one sticky slot per viewport edge.
Known interface gaps
Recorded from the MOL-59 audit cascade. None block the catalog entry; each must be closed before real storefront wiring:
- Missing
localeprop — FR/EN CTA labels and price formatting (storefront usesIntl.NumberFormatwithfr-CA/en-CA). - Currency default mismatch —
patterns.tsdocuments'USD';PriceTagdefaults'CAD'; the whole platform is CAD. - No sold-out / sale-window state —
EventTicketListcomputessoldOut/notOnSaleYet/saleEnded; a bar with only enabled /isLoadingshows a live "Buy Now" for a sold-out event. - No overridable CTA labels — docs hardcode
'Buy Now'; storefront uses next-intl. - No
privateLinkTokenextension for private-link event pages. - No scroll-visibility / z-index contract — the retired mobile language FAB no longer competes for the overlay layer (ADR-038).
- No mobile safe-area padding — zero
env(safe-area-inset-bottom)usage in the monorepo.
Accessibility
Planned contract (no implementation exists to audit yet): the CTA exposes an aria-label including the event name (WCAG 4.1.2 — a patterns.ts assertion); the bar root is role="complementary"; the price is announced as one text token via PriceTag (WCAG 1.3.1), never color-only; the CTA keeps a ≥44×44px tap target (--ep-tap-min, WCAG 2.5.5) and sets aria-busy while loading; the sticky bar must not obscure content — the host reserves bottom spacing and keeps the bar's controls after the page content in DOM order so keyboard Tab order is predictable.
Props
eventName*stringEvent title shown in the bar; also part of the Buy Now button's accessible name.
eventDate*stringEvent date label shown under the title (pre-formatted, locale-appropriate string).
priceFrom*numberLowest available ticket price in the currency's major unit; must be a positive number (NASA Rule 5).
currencystring'USD'ISO 4217 currency code forwarded to the price formatter. patterns.ts records 'USD'; the composed PriceTag atom defaults to 'CAD' — pass currency explicitly until the defaults are reconciled.
onBuyNow*() => voidFired when the Buy Now CTA is activated; the host routes to checkout / ticket selection.
isLoadingbooleanfalseForwards to the Button atom's loading — disables the CTA and sets aria-busy during the checkout transition.
Props
QuickBuyBar
eventNamestring—eventDatestring—priceFromnumber—currencystring'USD'onBuyNow() => void—isLoadingbooleanFalse<QuickBuyBar />Accessibility
Type
1 ruleARIA
1 ruleUsage
Import
import { QuickBuyBar } from "@epasslive/design-system"Example 1
<QuickBuyBar />Example 2
<QuickBuyBar variant="default" />Anti-patterns
— Do not hardcode data in molecules
— Avoid complex business logic in molecules