Skip to content

Anchor ​

Tracks the current section on scroll and highlights it automatically; clicking an anchor smooth-scrolls to the target. Supports custom scroll containers, click landing offsets, multi-level nesting, horizontal direction, affix, a moving ink bar, style variants and history control.

Basic usage ​

scroll-container points to a local scroll container (selector or element id): both the observation root and the click landing target use it; when unset the viewport is used.

Scroll spy (scroll-container)

Chapter 1

Section 1 content: demonstrates scroll spy and highlight tracking.

Chapter 2

When scrolled into view, the anchor highlights the current section.

Chapter 3

Click an anchor to smooth-scroll to the corresponding section.

Highlight offset and trigger boundary ​

offset controls the highlight detection line (how early a section's top crosses the line); bounds is an extra lead for the trigger boundary (default 5) to avoid highlight flicker.

Highlight offset (offset / bounds)

Chapter 1

offset controls the offset of the top highlight detection zone.

Chapter 2

The highlight switches earlier when a section top crosses the offset line.

Trigger boundary (bounds)

Chapter 1

A larger bounds triggers the highlight switch earlier.

Chapter 2

Default is 5px; set to 40px here so the switch point difference is visible.

Click events ​

oas-click and oas-change are separate: clicking an anchor fires oas-click (detail: { href, item }); both clicks and scroll-driven highlight changes fire oas-change (detail: { href, prevHref }) — listen to oas-click when you want to react to user actions only.

Click events (oas-click / oas-change separation)

Chapter 1

Click a left anchor: only oas-click fires. Scroll this container to switch highlights: only oas-change fires.

Chapter 2

oas-click carries the full item (href/title etc.).

Nothing clickedNo oas-click yet

Controlled highlight ​

active is a controlled attribute: an external set/remove of active directly controls the currently highlighted item (the scroll spy still takes over as you scroll).

Controlled active

Highlight Chapter 1Highlight Chapter 2Highlight Chapter 3Clear highlight

Chapter 1

Click a left button to set active; the anchor highlights the corresponding item immediately.

Chapter 2

When scrolling this container, the scroll spy takes over highlighting.

Chapter 3

"Clear highlight" removes active, restoring the no-highlight state.

Click landing offset and alignment ​

target-offset controls the distance between the target and the container top after clicking (avoids fixed headers); it falls back to offset when unset. block controls the landing alignment (start / center / end / nearest — nearest does not scroll when the target is already fully visible, minimal scroll); duration controls the smooth scroll duration, while animation="false" or duration="0" jumps instantly.

Click landing (target-offset / block / duration / animation)

Chapter 1

The dashed line marks the 80px landing line: after a click Chapter 1 aligns to it.

Chapter 2

duration=500 smooth-scrolls over about 500ms.

Landing alignment (block)

Chapter 1

block="center": the target section is vertically centered in the container.

Chapter 2

Click me to see the centered landing.

Minimal scroll landing (block=nearest)

Chapter 1

block="nearest": no scroll at all when the target is already fully visible.

Click "Chapter 3" first to scroll to the bottom, then click "Chapter 1" — if Chapter 1 is already visible nothing scrolls (minimal scroll).

Chapter 2

A target below the container scrolls just enough for its bottom to appear.

Chapter 3

A target above the container scrolls just enough for its top to appear.

Instant landing (animation)

Chapter 1

animation="false": clicking jumps to the target instantly, no smooth transition.

Chapter 2

Equivalent to duration="0".

Nesting and target markers ​

items supports children for multi-level nesting (indented; child items take part in scroll highlighting). <oas-anchor-target> marks scroll targets component-style (its id is synced to the inner part=target element) instead of hand-writing heading ids. internal-scrollable makes the anchor list itself internally scrollable.

Nesting (children / oas-anchor-target / internal-scrollable)

Chapter 1

Headings wrapped by oas-anchor-target serve as scroll landing targets.

1.1 Section

Child anchors are indented and take part in highlight detection.

1.2 Section

Child anchors are indented and take part in highlight detection.

1.3 Section

Child anchors are indented and take part in highlight detection.

1.4 Section

Child anchors are indented and take part in highlight detection.

1.5 Section

Child anchors are indented and take part in highlight detection.

Chapter 2

internal-scrollable: the anchor list scrolls internally when it overflows.

Horizontal direction ​

Horizontal (direction=horizontal)

Chapter 1

In horizontal mode the items are laid out in a row and the ink bar slides horizontally.

Chapter 2

Scroll the container to observe highlight switching.

Chapter 3

Clicking an anchor still lands on the section.

Affix ​

affix pins the anchor bar while scrolling (sticky positioning); affix-offset is the distance from the viewport top when affixed. This demo watches the viewport scroll.

Affix (affix / affix-offset)

Chapter 1

Scroll the page down: the left anchor bar sticks 16px below the viewport top.

Chapter 2

The highlight follows the current section as the page scrolls.

Chapter 3

Pair affix-offset with a fixed page header to clear it.

Style variants and sizes ​

Style variants and sizes (variant / size)

default

underline

lineless

block

size=small

size=large

History control ​

Clicking an anchor updates the URL hash by default (history.pushState); replace switches to replaceState; hash="false" writes nothing.

History control (hash / replace)

Chapter 1

Three anchors watch the same container: default pushState, replace via replaceState, and hash=false writes nothing.

Chapter 2

Click the first column's anchors to watch the URL hash change.

Nothing clicked

Custom highlight ​

get-current-anchor names a global function that receives the scroll-computed candidate href and returns the href to actually highlight; framework users can also pass a function via the getCurrentAnchor property.

Custom highlight (get-current-anchor)

Chapter 1

No matter where you scroll, the custom strategy forces Chapter 3 to be highlighted.

Chapter 2

The event detail.href also comes from the custom strategy.

Chapter 3

The actually highlighted item.

Not scrolled yet

Setting target (e.g. _blank) on an item leaves the default behavior to the browser (with rel="noopener noreferrer" added automatically) and excludes it from scrolling/highlighting.

External links (item target)

Declarative child channel ​

Besides the items JSON, you can write items declaratively with <oas-anchor-item> (the items attribute wins when explicitly set). The default slot text is the title; attributes map to the AnchorItem fields: href/target/target-offset; direct child <oas-anchor-item> elements recurse into children multi-level nesting (indented, and they participate in scroll highlighting too). Child additions/removals, attribute and text changes re-render automatically.

Child channel basic

Chapter 1Chapter 2

Chapter 1

Write anchor items declaratively with oas-anchor-item; scroll highlighting behaves the same as the items channel.

Chapter 2

Clicking an anchor scrolls smoothly to the target section.

Nesting and attributes (children / target-offset)

Chapter 1 1.1 Sub-section1.2 Sub-sectionChapter 2

Chapter 1

1.1 Sub-section
1.2 Sub-section

Chapter 2

A per-item `target-offset` overrides the global landing offset; child items also participate in scroll highlighting.

Scroll to the bottom of this section and watch the left-side highlight follow.

Click "Chapter 2" on the left to smooth-scroll to this section.

Extra content to make the container overflow and scroll.

One more paragraph to ensure scrollability.

API ​

oas-anchor ​

Attributes ​

AttributeDescriptionTypeDefault
activeCurrently highlighted href (controlled: external set/remove takes effect immediately; the scroll spy writes it back)string—
affixEnable affix (sticky positioning, sticks to the scroll viewport/container)boolean—
affix-offsetDistance from the scroll viewport top when affixed (px)string0
animationSmooth scroll switch (default true; false jumps instantly)stringtrue
blockScroll landing alignment: start / center / end / nearest (does not scroll when the target is already fully visible — minimal scroll; aligns to top when above, to bottom when below)ScrollBlockstart
boundsTrigger boundary (px, default 5): extra lead for a section's top crossing the detection line, avoids highlight flickerstring5
directionLayout direction: vertical / horizontalstringvertical
durationSmooth scroll duration in ms (default 300; 0 jumps instantly)string300
get-current-anchorCustom highlight strategy: attribute names a global function that receives the computed candidate href and returns the actual href to highlight; the getCurrentAnchor property also accepts a function((activeHref: string) => string) | null—
hashWhether clicking updates the URL hash (default true; false disables)stringtrue
internal-scrollableMake the anchor list itself internally scrollable (max-height + overflow-y: auto)boolean—
itemsAnchor items JSON; items support children (multi-level nesting), target (e.g. _blank) and per-item targetOffsetAnchorItem[] | string[]
offsetHighlight detection offset in px: how early a section's top crosses the detection linestring0
replaceHistory control: use history.replaceState instead of pushStateboolean—
scroll-containerScroll container selector or element id; when unset the viewport (window) is usedHTMLElement | string | null—
sizeSize: small / medium / largestringmedium
target-offsetClick landing offset in px (avoids fixed headers); falls back to offset when unset; per-item targetOffset winsstring—
variantStyle variant: default (rail + moving ink) / underline (sliding underline) / lineless (no axis) / block (filled background)stringdefault

Events ​

EventDescription
oas-changeFired on highlight change (both click and scroll-driven), detail: { href, prevHref }
oas-clickFired when a user clicks an anchor item (separate from the scroll-driven oas-change, so hosts can react to user actions only; also fires for external-link target items), detail: { href, item }

oas-anchor-target ​

Attributes ​

AttributeDescriptionTypeDefault
idTarget marker id: synced to the inner part=target element, used by anchor items as the scroll landing target——

Slots ​

NameDescription
defaultThe marked target content (e.g. multi-level headings)

oas-anchor-item ​

Attributes ​

AttributeDescriptionTypeDefault
hrefAnchor target: #id (or an external URL; combine with target for external links)——
targetLink target (e.g. _blank): when set, the default browser behavior is not intercepted (rel="noopener noreferrer" is added automatically)——
target-offsetPer-item click landing offset (px), overriding the global target-offset; invalid values are ignored——

Slots ​

NameDescription
defaultAnchor item title content (default slot text; direct oas-anchor-item children are excluded)

Scroll spy based on the scroll container (viewport by default); clicking smooth-scrolls to the target; nav + aria-label="Anchor navigation", the current item has aria-current="true".

A target marker component: wraps real multi-level headings and serves as the scroll landing target for anchor items; the default slot carries the marked content.

Released under the MIT OR Apache-2.0 License.