Announcement bar
The line at the very top of a site, for what cannot wait until the footer: a delivery offer, a closing day, a new catalogue.
Documentation
-
Copy to Webflow
Add Geist and Geist Mono to your site's fonts (Site settings, Fonts, Google Fonts) before pasting: Webflow removes any font your site has not installed. -
Add custom CSS
Custom CSS in WebflowThis CSS already ships inside the Webflow embed, so a pasted section needs nothing added. Paste it yourself, in the page or the site custom code, only if the effect runs on several pages. The tutorial explains where.
See the tutorialThe bar is a box of your own: its classes give its colours, its type and the padding of the list, which is its height. Do not give the list a height: it is as tall as its tallest message. Keep the bar first in the page, above the header, and put it with its Embed in the component that holds your navigation, the Embed right after the bar, so a visitor who closed it never sees it flash. The block named "Header of the preview" and the two screens are the demo around the bar: delete them on your site, and keep the bar and the Embed. The counter and the close are Link blocks, because Webflow has no button that holds layers; the script gives each the role and the keys of a button. -
Add custom JS
Custom JavaScript in WebflowThis script already ships inside the Webflow embed, settings block included. You paste it yourself, before the closing body tag of the page or the site custom code, only when the effect has to run on several pages, and the tutorial says how to choose.
See the tutorial -
Use it on your own elements
How to add a custom attribute in WebflowA custom attribute is a pair, a name and a value, typed in the Settings panel of the element you selected, under Custom attributes. The name is what the script looks for, the value is what it reads. The tutorial shows the panel.
See the tutorialCustom attributesSelect the element on the canvas and open the Settings panel. Under Custom attributes, add a pair: the name on the left, the value on the right.Custom attribute What it does data-announcement-bar Goes on the bar, the block at the very top of the page that holds the messages and the close, and takes no value: leave the value field empty. The settings below go on the same element. data-announcement-bar-list On the block that holds the messages. It takes no value. Every element directly inside it is one message, a paragraph with or without a link: add one or remove one freely, the engine reads the list. With a single message the bar does not relay. [ Required ] data-announcement-bar-close On what closes the bar, a word or a thin cross. It takes no value. The closing is stored in the browser for the setting days, and holds until a word of the messages changes. Without it the bar cannot be closed. [ Optional ] data-announcement-bar-count On the counter, which is also what brings the next message. It takes no value. Write its text as it should read on the first message, 1 / 3 or 01 / 03: the engine keeps the pattern and writes the real numbers. With a single message it keeps its place and shows nothing. [ Optional ] data-announcement-bar-follow On an element of your own that is held to the top of the window with position: fixed, a header for one. It takes no value. The stylesheet gives it a top equal to what is left of the bar in the window, so it sits under the bar and rises with the page. The Sticky header of this bank needs no mark: it is followed already. [ Optional ] data-announcement-bar-state, data-announcement-bar-current, data-announcement-bar-leaving, data-announcement-bar-single Written by the engine: on the bar, open, closing, closed or opening, and single when it holds one message; on the message on show, current, and on the one being covered, leaving. Never written by hand; the stylesheet reads them, and so can a rule of yours. [ Optional ] data-announcement-bar-roll, data-announcement-bar-status Written by the engine: on the box it puts around the figure of the counter, and on the line it adds to the bar for a screen reader. Never written by hand, and removed by destroy(). [ Optional ] data-announcement-bar-guard Written on the root of the page when a closing is stored, by the few lines of script the markup carries above the bar and by the engine as it loads; the stylesheet keeps a bar out while it is there, and the engine removes it once every bar is mounted. Never written in the markup. [ Optional ] SettingsEvery setting is a custom attribute too, added the same way and on the same element. An attribute always wins over the defaults written in the code.Attribute Default What it is data-announcement-bar-every 5 Time, in seconds, a message stays before the next one rises over it. The count starts again each time the relay resumes, after the pointer or the keyboard has left the bar. data-announcement-bar-travel 1 Time, in seconds, a message takes to rise over the last one. The counter rolls its figure in the same time. data-announcement-bar-leave 0.8 Time, in seconds, the page takes to come up over the bar when it is closed, and to go back down when it is brought back. data-announcement-bar-key announcement-bar Name the closing is stored under, inside the one entry announcement-bar of the browser storage. Two bars that must be closed apart, one for the shop and one for the blog, need two names; the same bar repeated on every page keeps one. Options: any short text. data-announcement-bar-days 30 How long a closing is kept, in days, in localStorage. Whatever the number, the closing only holds for the words that were closed: change a message and the bar is back. data-announcement-bar-label Announcements Name of the bar for a screen reader, written as its aria-label when the bar has none. Options: any text, in the language of the page. data-announcement-bar-next Next message What a press on the counter does, said to a screen reader after the figures: "2 / 3, Next message". Options: any text, in the language of the page.
Two files and their pictures (1), no build step.
It runs in the browser only. Load it with a script tag in plain HTML, in a
client-side script in Astro, never in the frontmatter. In React, call
AnnouncementBar.mount(ref.current) in useEffect and
destroy() in its cleanup.
-
Tune it, either way
Per element with an attribute, or once for the whole site by editingDEFAULTSat the top of the file.Attribute Default What it is Lower Higher data-announcement-bar-every 5 Time, in seconds, a message stays before the next one rises over it. The count starts again each time the relay resumes, after the pointer or the keyboard has left the bar. At 0 the messages never relay on their own, and the counter is the only way to the next one; under 3 nobody finishes reading a sentence Past 10 most visitors have scrolled away before the second message data-announcement-bar-travel 1 Time, in seconds, a message takes to rise over the last one. The counter rolls its figure in the same time. At 0 the messages change with no travel; under 0.5 the rise reads as a blink Past 1.6 the bar seems to be loading something data-announcement-bar-leave 0.8 Time, in seconds, the page takes to come up over the bar when it is closed, and to go back down when it is brought back. At 0 the bar is gone at once and the page jumps up by its height Past 1.4 the page is still moving when the visitor has gone back to reading data-announcement-bar-key announcement-bar Name the closing is stored under, inside the one entry announcement-bar of the browser storage. Two bars that must be closed apart, one for the shop and one for the blog, need two names; the same bar repeated on every page keeps one. Options: any short text. data-announcement-bar-days 30 How long a closing is kept, in days, in localStorage. Whatever the number, the closing only holds for the words that were closed: change a message and the bar is back. At 0 the closing is kept in sessionStorage, for one visit: the bar is back when the tab is closed and opened again Past 365 the bar is closed for good, until its words change data-announcement-bar-label Announcements Name of the bar for a screen reader, written as its aria-label when the bar has none. Options: any text, in the language of the page. data-announcement-bar-next Next message What a press on the counter does, said to a screen reader after the figures: "2 / 3, Next message". Options: any text, in the language of the page. -
Drive it from JavaScript
When something else on the page has to move the bar: a link of the footer that brings it back, a message shown from a script, a video that pauses the relay.const element = document.querySelector('[data-announcement-bar]'); element.addEventListener('announcementbar:change', (e) => { console.log(e.detail); }); const bar = AnnouncementBar.mount(element); // the bar auto() mounted, or a new one bar.next(); // bar.previous(), bar.go(2) bar.pause(); // bar.play() bar.close(); // stores the closing; bar.open() brings it back element.addEventListener('announcementbar:change', (e) => { console.log(e.detail.index); }); // When the bar leaves the page: bar.destroy(); // removes what the engine added and gives the markup back as it was
-
Fit it to your page
- Structure:
data-announcement-baron the bar, and inside itdata-announcement-bar-liston the block that holds the messages. Every element of that block is one message: a paragraph, with or without a link. That is all the engine needs. - Make it yours: write your messages. Add a paragraph, there is one more message; leave a single one, the bar stops relaying and the counter shows nothing. The colours, the height and the type are the classes of the bar.
- The close:
data-announcement-bar-closeon a button, a word or a thin cross, anywhere in the bar. Without it the bar cannot be closed, and Escape does nothing. - The counter:
data-announcement-bar-counton a button, written as it should read on the first message:1 / 3,01 / 03,1 of 3. The engine keeps the pattern, writes the real numbers, and a press brings the next message. Optional. - Where the bar goes: first in the page, above the header, in the flow. It takes its own height. On a site whose pages share a navigation, put it in that shared block, above the header, and the closing holds from page to page.
- Where the script goes: the stylesheet in the
head, the engine where you load your scripts, the end of thebodyincluded. The few lines of script written above the bar in the markup are what keeps a bar that was closed from showing for an instant while the engine loads: they mark the root when a closing is stored, and the stylesheet keeps the bar out until the engine has compared the words. Leave them above the bar. Without them, load the engine right after the bar or in thehead, withoutdefer. - With a header held to the window. A header that is
position: stickyand follows the bar in the flow, as in the preview, needs nothing. A header that isposition: fixedwould lie over the bar: the engine writes on the root, as--announcement-bar-inset, how much of the bar is still in the window, and the stylesheet gives that to thetopof the Sticky header of this bank, or of anything you markdata-announcement-bar-follow. The header sits under the bar, reaches the top as the bar scrolls away, and rises with the page when the bar is closed. With the Sticky header, give the bar the tone of the section that follows it,data-sticky-header-tone="dark"over a dark opening screen. - The keyboard: Tab goes through the counter, the link of each message and the close; reaching the link of a message that is not on show brings it up, and the relay waits while the keyboard is in the bar. Escape closes the bar, and the focus goes on to what follows it in the page.
- A screen reader finds a region named by the setting
labeland reads every message in it, in order, since they all stay in the page. Nothing is announced when the messages relay on their own; after a press on the counter the message that came up is read out. - Bring it back:
AnnouncementBar.reset()forgets every closing and opens every bar, for a link "Show the announcements" in a footer. - On Webflow, the messages are plain paragraphs on the canvas. The Designer runs no Embed, so the list shows every message, one under the other, where you edit them like any other text. The published page stacks them in one place. Put the bar and its Embed in the component that holds your navigation, the Embed right after the bar.
- Structure:
-
Avoid the pitfalls
- The messages are the direct children of the list. A wrapper between the list and the paragraphs makes one message of them all.
- Do not give the list a height. It is as tall as its tallest message, which is what keeps the page still from one message to the next. On a phone a long message wraps and the bar is as tall as that message for all of them: write messages of about the same length, or accept the room.
- Do not hide the bar yourself with a class or an interaction to close it: the engine closes it, and stores the closing. A bar hidden by something else is not remembered.
- A bar closed by a visitor comes back when a word changes, a link address included. Fixing a typing mistake shows the bar again to everyone who had closed it.
- **The bar must not carry a
margin-bottom, aclip-pathor atransformof its own while it closes**: the engine writes the first two on it for the time of the closing, and removes them. - **A parent of the bar with a
gap** between the bar and what follows it, a flex column for one, keeps that gap until the bar is gone, and gives it up at once at the end: a small step. Put the room inside the bar or inside the header instead. - Only a bar at the very top of the page moves a fixed header. A bar placed lower writes no inset.
- The storage may be refused, in a private window of some browsers: the closing then lasts as long as the page.
- In a framework that owns the DOM, mount in an effect and call
AnnouncementBar.destroy(el)in its cleanup: the engine adds a figure to the counter and a status line to the bar, and takes them back.
One click on Copy the AI prompt copies everything an assistant needs to build this effect: the complete code, the markup, the dependency, every setting and every pitfall.
What it does
Announcement bar is a site utility component for Webflow and vanilla JavaScript, with no library. Also called rotating announcement bar, dismissible banner with close button or top bar that remembers it was closed.
The line at the very top of a site, for what cannot wait until the footer: a delivery offer, a closing day, a new catalogue. You write the messages as a block of paragraphs, one per message, with or without a link. One message shows at a time. The next one does not push the last one out and does not fade in: it rises from the foot of the bar like a slip of paper laid over the one before, which sinks back a little, dims, and is cut along the edge of the slip that covers it. The counter beside it rolls its figure, and a press on it brings the next message. Closing uses the same gesture at the size of the page: the bar does not shrink, its words stay where they are, and the page comes up over it. The closing is stored in the browser, under a print of the words of the messages, so rewriting a message brings the bar back for everyone, and it is kept for the number of days you set, or for one visit. A visitor who closed the bar never sees it flash on the next page: the script marks the root as it loads and the stylesheet keeps the bar out until the words have been compared. The height of the bar is known before the script runs, since every message lies in the same place and the bar is as tall as the tallest of them: nothing moves when the script arrives, and nothing moves from one message to the next, on a phone either, where a long message wraps to two or three lines. The relay waits while the pointer is on the bar, while the keyboard is in it, while the tab is hidden and while the bar is out of the window. Every message stays in the page for a screen reader, which reads them all once, and nothing is announced when they relay on their own. A header held to the window, the Sticky header for one, sits under the bar and rises with the page. Under reduced motion the messages change and the bar leaves with no travel. Without the script every message shows, one under the other. Pattern type announcement bar, top bar, promo bar, notification bar, dismissible banner.
Updated
Questions
Paste the bar: a block marked data-announcement-bar with its messages, a close marked data-announcement-bar-close and one Embed that holds all the code. The closing is stored in the visitor's browser for the number of days of the setting days, 30 by default, and the bar does not show again on the next page. Put the bar and its Embed in the component that holds your navigation, so every page shares it.
Write one paragraph per message inside the block marked data-announcement-bar-list: the engine reads the list, so adding a paragraph adds a message. One shows at a time and the next rises over it after the setting every, 5 seconds by default. The relay waits while the pointer is on the bar or the keyboard is in it.
Here the stylesheet alone stacks every message in one place, so the announcement bar has its full height before any script runs and keeps it from one message to the next. A bar that was closed is kept out before it is drawn, when the script tag follows the bar or sits in the head without defer. Closing moves the page with an eased travel, not a jump.
Nothing to do: the closing is stored under a print of the words and link addresses of the messages, so rewriting one brings the announcement bar back for everyone who had closed it. AnnouncementBar.reset() forgets the closing of the current visitor, for a link in a footer, and data-announcement-bar-days="0" keeps a closing for one visit only.
Yes. A header that is position: sticky and follows the bar in the flow needs nothing. For a header that is position: fixed, the engine writes on the root how much of the announcement bar is still in the window, as --announcement-bar-inset, and the stylesheet gives it to the top of anything marked data-announcement-bar-follow: the header sits under the bar and rises with the page when the bar is closed.