Design System

Announcement bar

The thin dismissible strip above the site header. It is site-wide by decision — a bar that appears on one page reads like a bug — and it is mounted by SiteHeader, so it follows the marketing chrome exactly and never appears inside the intake funnel.

It renders server-side and hides on hydration, never the reverse. The first render always shows the bar, so a JS-disabled visitor and a crawler both get it and there is no hydration mismatch; the dismissal is read from localStorage after mount. A bar that only appears once JavaScript runs is a bar those two never see.

Two content rules are load-bearing. No financing promo while BNPL is inactive — the PDP still renders “Buy now, pay later” as a dead badge, and advertising a payment method that does not work is worse than saying nothing. And nothing whose truth depends on a price level: prices change from HQ without a deploy and nobody re-reads the announcement bar afterwards, so that failure would be silent. The shipping copy is the charge-timing promise, which is a property of how Halwel sells rather than of what it charges.

When the message changes, bump the storage key. Without it, every returning visitor who dismissed the previous message never sees the new one.

import from @halwel/ui/components/marketing/AnnouncementBar

Variants

Statement — the shipping default
Nothing is charged now. You pay only after a licensed provider reviews your intake and approves treatment.

the charge-timing promise, verbatim from the PDP microline

With a trailing mark
Shipped cold-chain from a 503A partner pharmacy[ mark ]

a node, not an image prop — so a partner mark implies no asset pipeline

Non-dismissible
Compounded medications are not FDA-approved.

for a notice that must stay — no dismiss control renders at all