Scroll Progress
ScrollA hairline along the top of the viewport that fills as the page is read.
A sticky navigation bar that condenses over the first 120 px of scroll: the row tightens and a hairline appears, bound to the document's scroll timeline. Zero JavaScript; where scroll timelines are missing it is a plain sticky bar with the hairline.
scroll inside
Line 1: the bar above condenses with the first 120 px of scroll.
Line 2: the bar above condenses with the first 120 px of scroll.
Line 3: the bar above condenses with the first 120 px of scroll.
Line 4: the bar above condenses with the first 120 px of scroll.
Line 5: the bar above condenses with the first 120 px of scroll.
Line 6: the bar above condenses with the first 120 px of scroll.
Line 7: the bar above condenses with the first 120 px of scroll.
Line 8: the bar above condenses with the first 120 px of scroll.
Live, from the library itself, at full size: scroll, hover, navigate away and back. The demo is never gated.
Variants · each row writes the attribute the prop writes; the section's own CSS answers
JavaScript of its own
0 B
CSS 7.6 kB raw including the base tokens. Measured from a production build, and again in CI for every change that can move it.
Browser support
Chrome 115 · not Firefox · Safari 26; needs scroll-timeline. Elsewhere: a sticky bar with the hairline that does not condense (Firefox).
The demo above is never gated; the source is. With a key in components.json (see account), the registry serves it like any other item:
npx shadcn@latest add @moonarc-pro/nav-bar---
import NavBar from '@/components/moonarc/pro/NavBar.astro';
---
<NavBar
brand={{ href: '/', label: 'Moonarc' }}
links={[{ href: '/components/', label: 'Components', current: true }, { href: '/docs/', label: 'Docs' }]}
action={{ href: '/setup/', label: 'Get started' }}
/>Without a key the registry answers 401 with an upgrade message.
| Prop | Type | Default | Description |
|---|---|---|---|
brand | { href, label } | none | Logo link. |
links | { href, label, current? }[] | none | Navigation links; current marks the active page. |
label | string | 'Primary' | Accessible name of the link nav. It must be unique per page, so change it when the bar is not the page's own (a preview, a second bar). |
action | { href, label } | none | Call to action at the end of the bar (the left in a right-to-left page). |
tone | 'surface' | 'muted' | 'ink' | 'brand' | unset (translucent card) | The ground: the page surface, a muted band, an always-dark ink panel, or a deep brand panel. Each paints --background, --ma-tone-muted (over --muted, with a --border hairline), --ma-tone-ink or --ma-tone-brand (over --primary) with the matching text. With theme.css, a painted tone also re-declares --card, --border, --input and --ring inside the section, so cards and fields follow the ground. Decoration is strongest on brand. |
density | 'compact' | 'cozy' | 'roomy' | 'cozy' | Bar padding ×0.8 / ×1 / ×1.25 through --ma-density. |
The section reads the theme contract (shadcn's variable names with the base tokens as fallback), so a pasted theme or one --ma-brand recolours it. Its class names are the override surface and stay stable; a named slot replaces the matching prop with your own markup.
.ma-navbar.ma-navbar__action.ma-navbar__actions.ma-navbar__brand.ma-navbar__inner.ma-navbar__links
slot="headline"slot="actions"
Always condensed, hairline always on.
ClientRouterCSS-only; the new page's bar starts at its own scroll position.
Replaces: Navbar (Tailwind Plus) · FloatingNav (Aceternity). See the migration table.
A hairline along the top of the viewport that fills as the page is read.
A menu bar whose panels open as popovers anchored under their triggers, columns revealing with a stagger, closing on Escape or outside click.
Also: view transitions · how costs are measured · browser support · accessibility policy · five-minute setup · MCP for agents · this page as Markdown