Skip to content

Guides

Render banners, popups and countdowns

Show the live banner and popup for a page, preview both on your website as editors type, tick countdowns on the CMS clock, and swap to a follow-up banner on time.

How-to guide3 min read

Fetch them

TypeScript
const { serverTime, items } = await cms.getBanners({ path, region })const popups = await cms.getPopups({ path, region, loggedIn })

Only entries live right now come back, already filtered for the page and for guests or signed-in visitors, pinned banners first.

Show the right banner

A banner may carry next: the banner that takes over when it ends, with startsAt. useCurrentBanner swaps to it on the second, by the CMS clock, without asking again:

Black Friday: 30% off00 : 00 : 05
28 Nov, 23:59 · the follow-up takes over on the second
Cyber weekend: 20% offuntil 1 Dec
The follow-up banner takes over the second the first one ends.
TypeScript
'use client'import { useCountdown, useCurrentBanner } from '@bifrost-orbit-cms/sdk/react'const banner = useCurrentBanner(items[0], serverTime)const left = useCountdown(banner?.countdown, serverTime)

Above or under the header

Editors choose a banner's Position: placement is aboveHeader or belowHeader. A page shows one banner, the first that targets it, in the position it asks for.

Asking per page means the layout has to know the address, which stops it being cached once for the whole site. Instead, read the banners for every page once, with the pages each one targets, and pick in the browser:

app/layout.tsxTypeScript
const banners = await cms.getBanners({ everyPage: true })<SiteBanner banners={banners} placement="aboveHeader" /><Header /><SiteBanner banners={banners} placement="belowHeader" />
TypeScript
'use client'import { usePathname } from 'next/navigation'import { bannerFor, useCurrentBanner } from '@bifrost-orbit-cms/sdk/react'export function SiteBanner({ banners, placement }) {  const banner = bannerFor(banners.items, usePathname(), placement)  const current = useCurrentBanner(banner, banners.serverTime)  // render current, or nothing when it is null}

bannerFor returns the banner for that page only when it asked for this position, so the same banner never shows twice, and drops a follow-up that targets other pages. Publishing a banner refreshes the cms:banners tag through the revalidate handler, so cached layouts pick it up straight away.

Preview banners on your website

When the space has a website preview address, a banner's editor shows your website, on the first page the banner targets, instead of a drawing of the banner. Wrap the banners in useLiveBanners and the banner being edited appears as the editor types, in the position they chose, before it is saved or scheduled:

TypeScript
const banner = bannerFor(useLiveBanners(banners)?.items, usePathname(), placement)

Mark the banner's outer element with data-cms-banner={banner.id} and the rest of the page is blurred in the preview so the banner stands out. Add data-cms-id={block.id} to the message, buttons and countdown so clicking them in the preview selects them in the editor.

Preview popups on your website

Popups preview the same way. A popup's editor shows your website on the first page the popup targets. useLivePopup returns the popup being edited, or null outside the editor, so show it in place of the one usePopup picked, straight away and whatever the visitor closed before:

TypeScript
const { popup: chosen, dismiss } = usePopup(popups.items)const live = useLivePopup()const popup = live ?? chosen

Mark the popup's outer element with data-cms-popup={popup.id} so the rest of the page is blurred in the preview, and add data-cms-id={block.id} to its blocks so clicking them selects them in the editor.

Countdowns

Countdowns arrive worked out. display says what to show now: countdown, a followUp, ended or hidden. useCountdown ticks every second, corrected by the server time, so a device set to the wrong time still ends the sale on time.

Popups

TypeScript
const { popup, dismiss } = usePopup(popups.items)

It picks one popup per page view and respects each popup's hide-for-days and maximum views.

Count views and clicks

With Insights Orbit, put the campaign's tracking label on the element that shows it, and render CmsInsights once in the layout:

TypeScript
<div data-banner={banner.trackingLabel ?? undefined}>…</div><section data-popup={popup.trackingLabel ?? undefined}>…</section>

Each labelled element sends a view once a page, and a click when a link or button inside it is used. Editors then see views, clicks and the goals reached after a click in the campaign's Results. See Insights Orbit.

Was this page helpful?

Read next