shadcn.io is not affiliated with official shadcn/ui
Trial Countdown Banner Block for Ark UI
A trial notice for a writing app: a clock, a sentence with the time left ticking, a line on what upgrading keeps, a Shine Button to upgrade and a dismiss button that folds the block away.
Installation
Overview
A trial countdown banner for React with Ark UI. One row between the page's rails: a clock, "Your Pro trial ends in 6d 23h 59m 59s" with the time left ticking, a line on what upgrading keeps, an outline Shine Button, Upgrade to Pro, and a ghost dismiss button. The time left is the text's own digits, each dropping into place as it changes; screen readers get it written out ("6 days, 23 hours, 59 minutes, and 59 seconds") from the same element. Dismissing folds the whole block away with a CSS height transition, down to its top rule, and leaves the keyboard where it was. It's built from Countdown Text, Guides, Shine Button and Button, with your theme's tokens for every colour. For free trials, grace periods and any time-boxed access. A usage bar and the payment-method line belong to a billing screen, not a banner.
FAQ
Where does the clock count to?
It counts a length of time, TRIAL_LEFT_MS at the top of the file (6 days and 23 hours), added to the time the browser has rendered the page; until then the countdown holds its width, unseen, so the server and the browser agree. For a real trial, set the target to your account's end date in the same effect that sets it now, never during render.
What does a screen reader hear?
The sentence, "Your Pro trial ends in", then the time left written out in words, from the same element that draws the digits. It isn't a live region, so nothing is read each second: people reach it by browsing. The countdown's digits are hidden from assistive technology and replaced by the words.
What happens when someone dismisses it?
The block's rows shrink from their full height to nothing while the notice fades, in 300 ms, and it ends at its top rule, so the next section's rule takes its place. Once folded, the notice is inert and hidden from screen readers, and the section drops its name. The dismiss button can't keep the focus, so focus moves to a short visually hidden line at the same spot, "Trial notice dismissed.", and the next Tab carries on from there. With reduced motion the block closes at once.
How do I keep it dismissed for the day?
The block forgets on purpose, so the preview always shows it. To remember, set a cookie in the dismiss handler and read it on the server, so the block is never rendered for someone who closed it. Reading localStorage after the first paint would show the banner and then fold it away, moving the page.
What happens at zero?
The sentence becomes "Your Pro trial has ended" and the line under it asks to upgrade to get unlimited projects and custom domains back. The button stays, so the one action is still there.
Where does the button go?
Upgrade to Pro is a link (href="#"): point it at your upgrade or billing page. It's an outline Shine Button, small, so it stays quieter than the page's main call to action.
It takes asChild with the link inside, so it can be your router's link.
What moves on a phone and with reduced motion?
Below md the clock, the text and the dismiss button share the first row, with the dismiss button in the top end corner, and the button takes its own row under them. A digit that changes drops into place; with reduced motion the digits change in place, and the entrance fade is off. Nothing scrolls sideways at 320 pixels.