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

@codefusion-cc/tailwind

v0.1.1

Published

Tailwind 4 spacing and dividers that Safari does not pay for: stack-y, stack-x, rule-y and rule-x without the :last-child selectors that make WebKit restyle the page on every DOM insertion, and a check that finds such selectors in an app's built CSS

Readme

@codefusion-cc/tailwind

Tailwind 4 spacing and dividers that Safari does not pay for, and a check that keeps the slow ones out.

Tailwind 4 writes space-y-4 as :where(.space-y-4 > :not(:last-child)) (and space-x-*, divide-y, divide-x the same way). Once a page has such a rule, WebKit – Safari, and every browser on iOS – restyles a whole subtree for each element added to or removed from the page. Measured on a shop page of 1,400 elements in WebKit: 41–49 ms for one inserted <div>, 0 ms without those rules. On a phone that is every drawer, toast, cart line and route change reacting late. The utilities here give the same spacing with a margin on every child after the first (:where(.stack-y-4 > :not(legend) + *)), which WebKit checks only on the children of .stack-y-4: 0 ms.

npm install @codefusion-cc/tailwind
@import 'tailwindcss';
@import '@codefusion-cc/tailwind/stack.css';

Tailwind also scans the repository's other text files for class names, README and scripts included: a sentence that mentions space-y-4 or divide-y brings the slow rule back. Keep the scan to the sources:

@import 'tailwindcss' source('.'); /* the folder of this CSS file, e.g. src/ */
@import '@codefusion-cc/tailwind/stack.css';

| Instead of | Use | | --- | --- | | space-y-4 | stack-y-4 (any number Tailwind's spacing takes: stack-y-1.5, stack-y-20) | | space-x-2 | stack-x-2 | | divide-y divide-gray-200 | rule-y rule-y-gray-200 (any theme colour) | | divide-x divide-gray-200 | rule-x rule-x-gray-200 |

Zero specificity, like Tailwind's: a child's own margin or border utility wins. The dividers are not called divide-* on purpose: tailwind-merge (twMerge, cn) would read divide-rows divide-rows-gray-200 as two divide colours and drop the first. Two differences from Tailwind's:

  • The gap is the margin above the next child, not below the previous one. After an inline child (a <label>, a link) or one out of the flow (absolutely positioned, sr-only) it shows, where Tailwind's never did: their own bottom margin moved nothing. Give such a container explicit margins, or make the child a block, when moving it over. Tailwind's sr-only is handled for you: the child after a legend or heading for screen readers only gets no gap, as with space-y.
  • A divider is the next child's top border instead of the previous child's bottom one: same line, same place, but inside the next child's box, which shows only when the children have backgrounds of their own.

In an app's tests

slowSelectors(css) (@codefusion-cc/tailwind/testing) lists the selectors in a stylesheet that WebKit checks on every element for its place among its siblings: a child-index pseudo-class (:last-child, :nth-child(), :first-of-type…) in a compound with no type, class, id or attribute of its own, directly or inside :is(), :where(), :not() or :has(). Tailwind's space-* and divide-*, :where(.list > :last-child) and .card :last-child are such selectors; .last\:border-0:last-child (Tailwind's last: variant) and li:last-child are not. Run it on the app's built CSS:

import { readFileSync } from 'node:fs'
import { fileURLToPath } from 'node:url'
import { compile } from '@tailwindcss/node'
import { Scanner } from '@tailwindcss/oxide'
import { slowSelectors } from '@codefusion-cc/tailwind/testing'
import { expect, it } from 'vitest'

it('has no CSS that makes WebKit restyle the page on every insertion', async () => {
  const entry = new URL('../src/index.css', import.meta.url)
  const compiler = await compile(readFileSync(entry, 'utf8'), { base: fileURLToPath(new URL('.', entry)), onDependency: () => {} })
  const candidates = new Scanner({ sources: [{ base: process.cwd(), pattern: '**/*', negated: false }] }).scan()
  expect(slowSelectors(compiler.build(candidates))).toEqual([])
})

It returns each selector once, in order, and an empty array for clean CSS; it never throws.