Dependency-free TypeScript plugin

Make horizontal overflow easier to discover

A11y Scroll Cue adds a visible text hint and an overflow-only keyboard tab stop to wide tables, code samples, card strips, and other semantic content—without replacing native scrolling.

Quick facts

Small surface, explicit behavior

Package
a11y-scroll-cue
Current version
1.0.0
Runtime
Browser · ESM
Dependencies
None
Best for
Semantic horizontal scroll regions

Live demos

Test the cue in context

Both pages use the compiled package from dist. Start with the basic patterns, then test a resettable real-world workflow.

Pattern sampler

Tables, code, and cards

Compare the same progressive enhancement across three kinds of semantic, horizontally overflowing content.

SaaS control room

Accessibility audit queue

Review a wide release table, dismiss the cue by scrolling, and restore it with a status-aware reset control.

Installation

Add the package and its default styles

The package is ESM-only and does not initialize anything when it is imported.

npm install a11y-scroll-cue

Basic usage

Keep the scrollport explicit

The original content remains available without JavaScript. The generated cue sits beside—not inside—the scrollable content.

HTML

<div
  data-a11y-scroll-cue
  data-a11y-scroll-cue-region-label="Feature comparison"
>
  <div data-a11y-scroll-cue-scrollport>
    <table>...</table>
  </div>
</div>

JavaScript

import { createA11yScrollCue } from "a11y-scroll-cue";
import "a11y-scroll-cue/styles.css";

const root = document.querySelector("[data-a11y-scroll-cue]");

if (root instanceof HTMLElement) {
  createA11yScrollCue(root, {
    regionLabel: "Feature comparison",
  });
}

Options

Configure content and semantics

JavaScript options override matching data attributes. Invalid booleans and negative or non-numeric thresholds fall back to the documented defaults.

Option Default Purpose
message "Scroll horizontally" Sets the visible cue text.
threshold 2 Sets the overflow tolerance in CSS pixels.
hideOnScroll true Dismisses the cue after real horizontal scrolling.
focusable true Adds a tab stop only while overflow exists.
observeMutations true Rechecks overflow after relevant content changes.
regionLabel Empty string Names an overflowing focusable region when needed.
describeScrollport false Links the visible cue through aria-describedby.

API and lifecycle

Initialize, update, dismiss, reset, or destroy

createA11yScrollCue()

Enhances one root and returns the same instance if called again for that element.

initA11yScrollCueAll()

Enhances every matching root in a document or supplied subtree.

update() and reset()

Reconcile overflow state or make an eligible cue visible again.

dismiss() and destroy()

Hide the cue deliberately or fully restore plugin-added state.

Lifecycle events

Successful initialization is synchronous: init → update → ready. The root also dispatches error, overflow-change, dismiss, reset, and destroy events. They bubble but are not cancelable or composed across Shadow DOM boundaries.

Accessibility behavior

Native scrolling stays in charge

Keyboard interaction

Key Behavior
Tab Reaches the scrollport only while it has horizontal overflow.
ArrowLeft / ArrowRight Uses the browser’s native horizontal scrolling behavior.
Home, End, and page keys Remain browser-controlled; the plugin does not intercept them.

Styling hooks

Theme the cue with custom properties

Import the package stylesheet, then override public properties on .a11y-scroll-cue. Default transitions respect prefers-reduced-motion.

.a11y-scroll-cue {
  --a11y-scroll-cue-background: Canvas;
  --a11y-scroll-cue-color: CanvasText;
  --a11y-scroll-cue-border-color: currentColor;
  --a11y-scroll-cue-hint-background: Canvas;
  --a11y-scroll-cue-hint-color: CanvasText;
  --a11y-scroll-cue-shadow: 0.25rem 0.25rem 0 currentColor;
  --a11y-scroll-cue-radius: 0;
  --a11y-scroll-cue-z-index: 2;
}

Limitations

What the plugin deliberately does not do