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

@fictjs/fict-remove-scroll-bar

v0.3.0

Published

Removes body scroll in Fict without layout shake.

Readme

@fictjs/fict-remove-scroll-bar

Body scroll-lock helpers for Fict, based on the react-remove-scroll-bar package.

It hides the page scrollbar by locking document.body, preserves the removed scrollbar gap, and ships the same helper class names for fixed or full-width elements that would otherwise jump.

The package is DOM-oriented. During SSR or other non-DOM execution it becomes a no-op.

Installation

pnpm add @fictjs/fict-remove-scroll-bar fict

Local demo

Inside this package directory you can run the bundled Vite demo:

pnpm example:dev
pnpm example:build
pnpm example:preview

The demo source lives in example/ and uses the package source directly.

Usage

/** @jsxImportSource fict */

import { render } from 'fict'
import { createSignal } from 'fict/advanced'
import { RemoveScrollBar } from '@fictjs/fict-remove-scroll-bar'

function App() {
  const open = createSignal(false)

  return (
    <>
      <button onClick={() => open(!open())}>Toggle lock</button>
      {() => (open() ? <RemoveScrollBar /> : null)}
    </>
  )
}

render(() => <App />, document.getElementById('app')!)

Mounting <RemoveScrollBar /> applies the lock. Unmounting it removes the lock, and nested mounts are reference-counted.

Helper class names

To keep fixed or full-width elements aligned when the body scrollbar disappears:

/** @jsxImportSource fict */

import {
  RemoveScrollBar,
  fullWidthClassName,
  noScrollbarsClassName,
  zeroRightClassName,
} from '@fictjs/fict-remove-scroll-bar'

function Sheet() {
  return (
    <>
      <RemoveScrollBar />
      <header className={zeroRightClassName}>Fixed action bar</header>
      <main className={fullWidthClassName}>Full-width layout</main>
      <aside className={noScrollbarsClassName}>Nested scroll container</aside>
    </>
  )
}
  • zeroRightClassName: offsets elements that normally use right: 0.
  • fullWidthClassName: offsets width: 100% layouts that need the missing scrollbar space back.
  • noScrollbarsClassName: hides scrollbars on a nested element and applies the same padding-right compensation.

The removed scrollbar width is also exposed through the CSS variable --removed-body-scroll-bar-size.

API

RemoveScrollBar

interface BodyScroll {
  noRelative?: boolean
  noImportant?: boolean
  gapMode?: 'padding' | 'margin'
}
  • noRelative: skips position: relative on the locked body.
  • noImportant: omits !important from injected rules.
  • gapMode: chooses whether the body gap compensation is applied through margin or padding. Default is 'margin'.

getGapWidth(gapMode?)

Returns the measured offsets and effective scrollbar gap:

{
  left: number
  top: number
  right: number
  gap: number
}

This is useful when a primitive needs the same compensation value for custom layout logic.

Fict-specific behavior

  • The component follows Fict's mount lifecycle rather than rerendering like React.
  • As with the original singleton package, the first mounted instance owns the injected stylesheet.
  • Changing noRelative, noImportant, or gapMode after mount does not restyle the existing singleton. Remount the component if you need different options.
  • Nested mounts still increment and decrement the body lock counter correctly.

License

MIT