KeepTrack-CSS is a zero-dependency browser library that reads computed CSS property values from elements and exposes them as CSS custom properties (variables). It supports scrollbar tracking, sticky detection, scroll-padding for anchor links, and more.
src/keepTrack.js — Source of truth (UMD format)
build.js — Build script (generates dist/)
dist/ — Generated output (not in git)
keepTrack.js — UMD copy
keepTrack.esm.js — ESM build
keepTrack.min.js — Minified UMD
keepTrack.min.js.map — Sourcemap for minified build
keepTrack.d.ts — TypeScript definitions
tests/ — Vitest test suite (happy-dom)
index.html — Demo page (GitHub Pages, served from root)
styles.css — Demo page styles
eslint.config.mjs — ESLint 9 flat config
vitest.config.mjs — Vitest config
CHANGELOG.md — Release changelog
- No runtime dependencies. The library runs in the browser only and must stay dependency-free.
- UMD source.
src/keepTrack.jsuses a UMD wrapper (AMD, CommonJS, global). The ESM build is derived from it automatically bybuild.js. - No TypeScript source. Type definitions in
dist/keepTrack.d.tsare generated bybuild.js, not compiled from.tsfiles. Keep them in sync manually when changing the public API. - No transpilation. The source targets modern browsers directly — no Babel, no bundler.
- Terser is the only dev dependency (used for minification).
npm run build # generates dist/ (UMD, ESM, min, min.js.map, d.ts)The prepare script also runs node build.js, so npm install from a git clone will build automatically.
npm run lint # ESLint 9 flat configConfig lives in eslint.config.mjs. Browser globals are set for src/, CommonJS globals for build.js. dist/, node_modules/, and docs/ are ignored.
npm test # vitest run (happy-dom environment)Tests are in tests/keepTrack.test.js. The UMD source is loaded via new Function() with a local module.exports so it runs in the happy-dom environment. Tests verify API shape, CSS variable placement, cleanup, observe/unobserve, scrollbar tracking, and callbacks.
Limitations: happy-dom's getComputedStyle returns empty strings and getBoundingClientRect returns zeroes. Tests check that variables are set, not their pixel values. Sticky detection is not meaningfully testable.
Releases are published to npm automatically via .github/workflows/release.yml when a GitHub Release is created (published).
Setup:
- Create an npm access token (Granular Access Token, publish-only, scoped to
keeptrack-css). - Add it as a repository secret named
NPM_TOKENin GitHub Settings > Secrets and variables > Actions. - Create a GitHub Release — the workflow runs build, lint, test and then
npm publish --provenance --access public.
The library exports a single factory function:
const tracker = new KeepTrack(options?)Returns an instance with: init(options?), destroy(), recalculate(), observe(el), unobserve(el).
| Option | Type | Default | Description |
|---|---|---|---|
scrollbarWidth |
boolean |
true |
Track --scrollbar-width on :root |
scrollbarHeight |
boolean |
false |
Track --scrollbar-height on :root |
debounceTime |
number |
250 |
Debounce delay (ms) for resize/DOM changes |
poll |
boolean |
false |
rAF polling for non-layout property changes |
detectSticky |
boolean |
false |
Detect stuck state of position: sticky elements |
stickyTopDynamic |
boolean |
false |
Recompute sticky top every frame instead of caching |
onChange |
function|null |
null |
Callback: (el, prop, value) => void |
data-keeptrack="height, width, ..."— comma-separated CSS properties to trackdata-keeptrack-target-parent="2"or".selector"— set variable on a parent/ancestor insteaddata-keeptrack-scroll-padding— include element's height inscroll-padding-top
- Always edit
src/keepTrack.js, neverdist/files directly. - Run
npm run buildafter changes to regenerate dist/. - If you change the public API (options, methods, return types), update the
dtsstring inbuild.jsto keep type definitions in sync. - Test changes using
index.htmlwhich covers all features interactively. - The demo page loads
src/keepTrack.jsdirectly (not the built version).