npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

overflowlint

v0.4.0

Published

Browser-based DOM layout linter: detects overflow, clipped text, covered elements, and more

Readme

OverflowLint

Runtime layout checks for rendered UIs.

OverflowLint turns live DOM geometry and browser hit testing into structured, actionable findings for developers, Playwright, and coding agents.

It detects document overflow, masked clipping, truncated text, covered controls, and undersized interactive targets on ordinary rendered pages. Baseline checks need no annotations. Optional data-ol-* contracts add product-specific intent.

Website · Interactive demo · Generated reference

Install

pnpm add -D overflowlint

The package is ESM. playwright is an optional peer and is only needed for the overflowlint/playwright adapter.

One rendered-page scan

import { OverflowLint } from 'overflowlint'

const result = OverflowLint.run({
  tolerance: 1,
  max_findings: 80,
  report_to_console: true,
})

if (result.summary.findings.error > 0) {
  console.error(JSON.stringify(result.findings, null, 2))
}

Every result is serializable and includes schema_version: 2, raw findings, root-cause groups, skipped-check counts, active contracts, suppressions, and suppression-policy violations. Every finding has a closed rule, stable fingerprint, category, static rule level, dynamic confidence, detection level, rectangle, typed evidence, and deterministic diagnosis/fix candidates.

Rule levels are essential, recommended, and experimental. They describe the maturity and intended future preset of a rule, not the certainty of one finding. All levels currently run by default. A finding's confidence remains the page-specific certainty signal.

Playwright: inject, scan, verify

Playwright injection is the primary test integration. check_page() installs the shipped panel-free core if necessary, waits for fonts and images, and lets the page settle: two animation frames plus any in-flight finite CSS transitions/animations (polled via document.getAnimations(), capped at 1s so spinners or looping effects never block a scan). It reuses an app-provided runtime when its schema_version is compatible.

Settling is configurable with settle: { animations: { max_wait_ms } } or disabled with settle: { animations: false }. Because findings depend on the current scroll position, check_page() also records it in report.scroll; pass scroll_to_top: true to reset to the top before scanning for reproducible results.

import { expect, test } from '@playwright/test'
import { check_page } from 'overflowlint/playwright'

test('has no high-confidence layout errors', async ({ page }) => {
  await page.setViewportSize({ width: 390, height: 844 })
  await page.goto('http://localhost:5173/example')

  const report = await check_page(page, {
    failure_policy: {
      severities: ['error'],
      minimum_confidence: 'high',
    },
  })

  expect(report.finding_failures, JSON.stringify(report, null, 2)).toEqual([])
  expect(report.suppression_failures).toEqual([])
})

inject_lint(page, { force?: boolean }) supports strict-CSP pages. A compatible runtime is reused; an incompatible one is rejected unless forced replacement is explicit. Suppression failures stay separate from DOM findings, so no fake zero-rectangle issue is created.

An application-owned watcher remains a supported alternative:

import { OverflowLint } from 'overflowlint'

const stop = OverflowLint.watch({
  report_to_console: false,
  on_result(result) {
    console.log(result.summary.groups.actionable)
  },
})

stop()

Only one watcher is active. While an ESM watcher runs, the singleton is attached to window.OverflowLint for browser tools; stop() removes that temporary global. The IIFE and userscript always expose the global.

Text robustness

Ordinary scans report observed failures and masked failures already present in the DOM. Text stress is explicit and asynchronous:

import { OverflowLint } from 'overflowlint'

const stressed = await OverflowLint.stress_text({
  profiles: ['expanded', 'unbroken', 'mixed'],
  max_candidates: 40,
  max_outcomes: 20,
})

console.log(stressed.stress?.passed)

The default profiles cover expanded copy, an unbroken token, and mixed Latin, CJK, emoji, and numeric text. Atomic url, numeric, emoji, and cjk profiles are also available. The scan mutates one visible text node at a time, waits for layout, records only new failures, and always restores the original text. Ellipsis and line-clamp behavior introduced by stress is returned as bounded graceful-degradation outcomes rather than failures. Detection levels are observed, masked, and text-stress.

Experimental runtime audits

Experimental rules currently run alongside the established rule set and emit mostly medium- or low-confidence warnings. They cover zero-area, clipped, transparent, pointer-disabled, and offscreen fixed controls; horizontal viewport escape; flex/grid item overflow; sibling content overlap; fixed/sticky obstruction; and informational DOM/z-index complexity.

Core findings include typed likely causes and fix candidates. A candidate may carry preview-safe CSS declarations such as min-width: 0 or overflow-wrap: anywhere; OverflowLint reports these declarations but never applies them automatically.

Optional contracts

Contracts are a second layer for intent the browser cannot infer reliably:

<main data-ol-no-scroll="x">
  <header data-ol-in-viewport>
    <button aria-label="Open navigation" data-ol-min-target="44">Menu</button>
  </header>

  <aside data-ol-min-visible="0.75" data-ol-contained-by="viewport">
    Account status
  </aside>

  <div data-ol-allow-scroll="x">
    <!-- Intentional horizontal scrolling -->
  </div>

  <nav data-ol-overlay-chrome>
    <!-- Persistent app chrome: never reported as covering content -->
  </nav>

  <aside data-ol-off-canvas>
    <!-- Hidden off-canvas drawer, e.g. translateX(-105%) -->
  </aside>
</main>

Prefer narrow allowances. data-ol-ignore removes an entire subtree from findings and hit-test occlusion, so suppression policies should audit broad exceptions in automated tests. data-ol-overlay-chrome marks persistent app chrome whose hit-test occlusion is intentional — it stops being reported as a covering element, but its own subtree still runs every check. data-ol-off-canvas declares an intentionally off-canvas element (hidden drawer) so it is not reported as a horizontal scroll-container leak; a position: fixed element whose box is fully outside the viewport on the x-axis is inferred the same way.

The complete contract and rule tables are generated from the source registries in docs/reference.md.

Rich diagnostics and viewport matrices

import {
  attach_lint_report,
  check_viewports,
  inspect_page,
} from 'overflowlint/playwright'

const report = await inspect_page(page, {
  diagnostics: 'deep',
  text_stress: true,
  fail_on_suppression_violations: true,
  lint_options: {
    suppression_policy: { disallow: ['ignore'], max: 2 },
  },
})

await attach_lint_report(testInfo, page, report, {
  // The PNG includes numbered, severity-colored failure boxes.
  screenshot: { annotate: true, max_findings: 20 },
})

const matrix = await check_viewports(
  page,
  [
    { name: 'mobile', width: 390, height: 844 },
    { name: 'desktop', width: 1440, height: 900 },
  ],
  {
    diagnostics: 'failures',
    failure_policy: { severities: ['error', 'warning'] },
  },
)

console.log(matrix.failures)

inspect_page() can add computed styles, hit-test stacks, text rectangles, ancestors, and likely overflow culprits. check_viewports() groups the same fingerprint across named viewports. Matrix runs scan from the top by default so responsive reflow cannot make later runs inherit a different scroll position; the original viewport and scroll position are restored afterwards. Set scroll_to_top: false only when intentionally testing the current scroll state. attach_lint_report() annotates screenshot attachments by default and removes its isolated overlay immediately after capture. Pass screenshot: { annotate: false } when a clean page image is preferable.

One horizontal overflow no longer cascades into a finding for every ancestor up to <html>. Unclipped inferred-scroll-overflow-x findings are collapsed to the deepest flagged element that explains the overflow (each scroll-container-leak-x finding stays independent because it models a distinct parent/child boundary); pass lint_options: { collapse_cascade: false } to keep the full raw cascade.

Browser tools and coding agents

The IIFE is useful for browser tools that can load an init script:

agent-browser --session ui \
  --init-script ./node_modules/overflowlint/dist/overflowlint.core.js \
  open http://localhost:5173
agent-browser --session ui set viewport 390 844
agent-browser --session ui --json eval \
  "OverflowLint.run({ report_to_console: false })"

For a version-pinned browser ESM import:

<script type="module">
  import { OverflowLint } from 'https://cdn.jsdelivr.net/npm/overflowlint@VERSION/+esm'
  OverflowLint.watch()
</script>

Privacy and security

Scans execute in the inspected page. OverflowLint has no telemetry and does not transmit page data. Panel clipboard writes only happen after a user presses a copy button.

Bookmarklets and userscripts execute broadly inside visited pages and can read those pages. Install them only from a source you trust. Prefer the npm package and Playwright injection for controlled development and CI environments.

Limitations

OverflowLint is a development aid, not a replacement for visual review, accessibility testing, responsive product judgment, or cross-browser testing. It does not traverse iframes, infer whether every intentional overlap is good, or prove that a clean layout is attractive. Geometry can change after a scan, and closed shadow roots remain opaque.

Use representative viewports and realistic content. Render, scan, fix, and rerun in the same state.

Distribution

Stable bookmarklets and userscripts load the latest published npm release from jsDelivr. The project website may describe unreleased main behavior. Dev channels track main and belong in advanced testing only. Pin npm versions for repeatable automation.

Development

Requires the pinned Node and pnpm versions.

pnpm dev
pnpm format
pnpm format:check
pnpm test:unit
pnpm test:browser
pnpm test:browser:all
pnpm test:performance
pnpm test:docs
pnpm test:package
pnpm verify

pnpm test is the fast coding loop: unit tests plus Chromium E2E, excluding the performance suite. pnpm test:browser:all runs the functional suite in Chromium, Firefox, and WebKit. Performance budgets run separately and serially with pnpm test:performance to avoid cross-browser CPU contention.

pnpm verify is the definition of done. It checks formatting, types, unit tests, all three browser engines, documentation, build artifacts, and a fresh packed consumer. When the adjacent Eva repository exists locally, verification also runs its typecheck.

License

MIT