Skip to content
Black FridayBlack Friday launch price: Lifetime $149 until 30 Nov. Regular price $299 from 1 Dec.ends in 15d 03:13:35Get Lifetime →
loopkit
proNew255 lines · framer-motion

Navbar Announcement

A promo strip that collapses away instead of snapping shut. A slim gradient announcement strip stacked above a clean main nav bar (logo, links, CTA); dismissing it animates height and opacity to zero via component state so the bar below settles up smoothly.

Use it for
Launch or update announcements, limited-time promos, or status notices above a standard product/marketing nav, where a hard `display:none` cut would feel jarring.
Themes
Light + dark
License
Commercial use
Live

Scheduling now runs on the new automation engine.

Product update

Every release, tracked from idea to ship.

See what changed, who shipped it, and what is still in review, all in one place.

Releases

What shipped this week, in plain language.

Roadmap

What is planned next and roughly when.

Status

Uptime and incidents, updated live.

Billing

Plan, usage and invoices in one tab.

tsx
"use client";

import * as React from "react";
import { AnimatePresence, motion, useReducedMotion } from "framer-motion";
import { cn } from "@/lib/utils";

function useReducedMotionSafe() {
  const prefersReduced = useReducedMotion();
  const [mounted, setMounted] = React.useState(false);
  React.useEffect(() => setMounted(true), []);
  return mounted ? !!prefersReduced : false;
}

/**
 * A slim dismissible announcement strip stacked above a clean main nav bar.
 * Dismissing animates height + opacity to zero (never `display:none`) via
 * component state, so it resets whenever the block remounts.
 */

export interface NavLink {
  label: string;
  href?: string;

The rest is in Pro.

Full source, the rebuild prompt and registry install unlock with Pro or Lifetime.

Get Pro

How it behaves

  • →The announcement strip is wrapped in AnimatePresence; dismissing it animates height (to/from "auto") and opacity together over ~0.35s instead of toggling display, so the nav bar below slides up cleanly.
  • →Dismiss state lives in local component state (defaultDismissed seeds it) — there is no localStorage, so it always reappears on remount, matching the live preview's Replay button.
  • →The arrow link and the close button are independent controls: the link is preventDefault-ed (no navigation) and the × button calls onDismiss and triggers the collapse.
  • →The main nav underneath is a plain bordered bar with a logo, centred links (hidden under 768px) and a filled CTA; a hamburger button opens a dropdown sheet positioned absolute inside the nav's own relative wrapper.
  • →prefers-reduced-motion shortens the collapse transition to effectively instant rather than removing it, since it is a one-shot state change, not a looping animation.

Accessibility

  • ✓The dismiss button has `aria-label="Dismiss announcement"`; the hamburger button has a dynamic `aria-label` and `aria-expanded`.
  • ✓Announcement text and the main nav links are real elements in reading order, so a screen reader announces the strip before the nav, matching the visual stack.
  • ✓All links `preventDefault` instead of navigating, keeping keyboard focus and activation behaviour native.
  • ✓Honours prefers-reduced-motion.