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

@litsx/tailwind

v1.0.0-next.8

Published

Bundler-neutral Tailwind CSS integration protocol for LitSX components

Readme

@litsx/tailwind

Tailwind CSS v4 utilities for LitSX shadow DOM and light DOM components. The root export is a build-tool-neutral LitSX integration. A separate /vite entrypoint keeps the existing adapter based on the official Vite plugin.

Installation

For Evolit or another neutral LitSX host:

npm install @litsx/tailwind

For Vite, install the optional peer tooling too:

npm install -D @litsx/tailwind @litsx/vite-plugin \
  @tailwindcss/vite tailwindcss vite

The Vite adapter supports Tailwind CSS 4.3+, Vite 7.3 or 8, and LitSX 1.0. Consumers of the neutral root entrypoint do not need Vite, @tailwindcss/vite, or an application-owned PostCSS pipeline.

Evolit quick start

// evolit.config.js
import { litsxTailwind } from "@litsx/tailwind";
import { defineEvolitConfig } from "evolit/litsx";

export default defineEvolitConfig({
  litsx: {
    compiler: { sourceMaps: true },
    integrations: [
      litsxTailwind({
        integration: { entry: "./src/tailwind.css" },
      }),
    ],
  },
});
/* src/tailwind.css */
@import "tailwindcss" source(none);

@theme {
  --color-brand: oklch(62% 0.18 255);
}

This single declaration contributes the native LitSX compiler plugins, materializes component and preflight virtual modules, watches the Tailwind entry and its imports, removes stale candidates, and declares the final document stylesheet. Evolit runs the same instance lifecycle for development, SSR, hydration, production and standalone execution.

Vite quick start

// vite.config.js
import { defineConfig } from "vite";
import { litsxTailwind } from "@litsx/tailwind/vite";

export default defineConfig({
  plugins: litsxTailwind({
    integration: {
      entry: "./src/tailwind.css",
    },
  }),
});
/* src/tailwind.css */
@import "tailwindcss" source(none);

@theme {
  --color-brand: oklch(62% 0.18 255);
}

The main @litsx/tailwind entrypoint is build-tool-neutral and uses Tailwind's public Node compilation API. It does not import Evolit, Vite, or @tailwindcss/vite. The /vite entrypoint remains available and composes the same compiler protocol with Tailwind's official Vite plugin.

source(none) is recommended because LitSX owns candidate routing. The entry still owns theme, preflight, plugins and custom CSS.

Public API

@litsx/tailwind/vite

litsxTailwind(options?) is the supported high-level Vite entrypoint and returns the complete ordered plugin array. Pass it directly inside plugins, as shown above. Its options are:

  • litsx: options forwarded to @litsx/vite-plugin;
  • tailwind: options forwarded to the official @tailwindcss/vite plugin;
  • integration: LitSX candidate-routing options documented below.

Advanced Vite integrations can compose the lower-level withTailwindViteCompiler() and createTailwindVitePlugins() helpers. Pass a shared context to both when another framework owns the LitSX plugin ordering, as Storybook does. Ordinary applications should use litsxTailwind().

@litsx/tailwind

The bundler-neutral entrypoint exposes:

  • litsxTailwind(options?), the complete single-declaration integration for Evolit and other hosts implementing the LitSX build lifecycle;

  • createTailwindBuildEngine(context) for lower-level neutral hosts;

  • createTailwindContext(options?) for the shared project-level candidate and virtual-module registry;

  • createTailwindAuthoringPlugin(options?) for authored class analysis;

  • createTailwindOutputPlugin(context, options?) for compiler-output routing;

  • withTailwindCompiler(options, context, integration?) to add both compiler contributions to an existing TransformLitsxOptions object.

Ordinary Evolit applications should use litsxTailwind(). Lower-level hosts must create one integration instance per server, build, or runtime. Candidate registries and compiler state are instance-owned, so concurrent projects and requests do not share mutable state.

The neutral integration declares two final outputs:

  • preflight.js, a virtual JavaScript module containing Shadow Root preflight;
  • global.css, one document stylesheet containing theme/custom properties, document preflight, Tailwind property registrations, and global utilities.

Component utilities remain in their individual virtual modules. Theme rules are removed from the Shadow Root preflight so variables are emitted once in the document and inherited across the shadow boundary. @property rules are likewise hoisted once to the document output. Authored Component.styles remain between preflight and generated utilities.

On invalidation the host can rebuild the affected virtual modules immediately; forget removes candidates for graph modules that disappeared, and dispose clears all instance state. Errors thrown by Tailwind retain the host's integration/hook/module context.

Component ownership

Literal and statically enumerable classes referenced by a component belong to that component. This includes constants, maps, ternaries and imported finite values:

const SIZE = {
  sm: "h-8 px-3",
  lg: "h-12 px-6",
};

export function UiButton({ size = "sm" }) {
  return <button class={SIZE[size]}>Save</button>;
}

For a shadow component, only these utilities are attached to its static Lit styles. A second component in the same source file does not receive them.

Free JSX outside a LitSX component class belongs to the document instead. This includes Storybook render functions and other light-DOM templates. In a mixed module, LitSX emits those utilities globally while keeping component-owned utilities in the component's own shadow or light-DOM destination:

export function UiCard() {
  return <article class="bg-brand p-4">Component</article>;
}

export const CardStory = {
  render: () => <section class="grid gap-3">Story</section>,
};

Here bg-brand and p-4 remain owned by UiCard; grid and gap-3 are generated in the global stylesheet. A class used by both destinations is generated in both because each destination must be independently usable.

Non-finite class construction needs a finite integration safelist:

function Swatch({ color }) {
  return <span class={`bg-${color}-600`} />;
}
litsxTailwind({
  integration: {
    safelist: ["bg-red-600", "bg-green-600"],
  },
});

Only entries matching this component's bg-*-600 pattern are included in its CSS. Unrelated safelist entries are not copied into the shadow root.

Component.styles remains an explicit local guard for utilities that cannot be reached from markup. Finite strings, arrays, objects and imported constants are consumed at build time; they are not emitted as CSS twice:

DynamicBox.styles = [baseStyles, { red: "bg-red-600", green: "bg-green-600" }];

Shadow and light DOM

Shadow components receive:

  • one shared preflight CSSResult;
  • one exact per-component utility CSSResult;
  • inherited Component.styles in their normal Lit order.

The document receives preflight/theme once and an inert infrastructure sheet. The latter lets Tailwind register global @property definitions needed by utilities such as shadow-*, ring-* and translate-*, including components loaded lazily. Its utility selectors are nested under an inert id and cannot style application markup.

Light DOM uses the compiler's normal policy:

  • global emits ordinary global utilities;
  • scoped emits utilities inside @scope (...) to (...), stopping at nested LitSX component roots;
  • React compatibility forces global, consistently with its light-DOM model.

Scoped light DOM requires native CSS @scope support (Chrome/Edge 118+, Safari/iOS 17.4+, Firefox 146+). Use global when targeting older browsers, including Firefox ESR 140.

Options

The root litsxTailwind() accepts integration, preflightOutput, and globalCssOutput. integration contains entry, sources, and safelist. The /vite function additionally accepts litsx and tailwind options for its two Vite plugins.

With /vite, sources feeds the shared infrastructure so lazy modules have the required Tailwind property registrations before they are imported. A neutral graph host such as Evolit discovers those registrations from all LitSX modules before finalize, so no extra source scan is needed. sources is not a fallback global utility scanner. Exact component utilities come exclusively from that component's markup, finite guards and matching safelist entries; utilities in free light-DOM JSX are routed separately to the global sheet.