A centred offer with the time left until it ends, as a bar across the page on a neutral fill.

Last updated

Open block
Show code
---
/**
 * Countdown, full width: A centred offer with the time left until it ends, as a bar across the page on a neutral fill.
 *
 * @block banner
 * @order 19
 */
import Banner from '@/components/apogee/sections/Banner/Banner.astro'
import Countdown from '@/components/apogee/Countdown/Countdown.astro'
import { plain } from '@/components/apogee/sections/_shared/spine.ts'
import type { BannerContent } from '@/components/apogee/sections/_shared/banner.ts'

/** @composable */
interface Props extends BannerContent {
  /** When the offer ends, as an ISO date-time. @category content */
  endsAt?: string
}

const {
  heading = '30% off annual plans ends soon',
  description = 'Lock in your price today.',
  endsAt = '2026-12-31T23:59:59Z',
  closeLabel,
} = Astro.props
---

<Banner layout="full-width" align="center" inline heading={plain(heading)} description={description ? plain(description) : undefined} closeLabel={closeLabel}>
  <Countdown slot="actions" to={endsAt} />
</Banner>

Add

npx @ava-ui/apogee add banner/countdown-full-width

Every piece of copy is a prop, with the sample copy as its default. Pass yours, or null to hide a part; see copy is props.

This copies the block to src/components/apogee/blocks/banner/ with everything it uses: Banner, Countdown. Place it at the top of a page, or pass fixed to a floating banner to pin it to the bottom of the viewport. Use Copy code above to paste it instead.

Accessibility

  • The banner is a region named by its message, so it shows up in a screen reader’s landmark list.
  • The close button removes the banner; it needs JS, so it hides without it and the banner stays.
  • Screen readers and no-JS visitors read the end date (“Ends Dec 31, 2026, 11:59 PM UTC”); the ticking numbers are hidden from them, so nothing is announced every second.