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

dyss

v1.2.1

Published

Dynamically create and update CSS stylesheets from JS

Readme

dyss

npm npm

A tiny utility to dynamically create and update CSS stylesheets from JavaScript.

dyss lets you generate CSS rules at runtime, update them efficiently, and avoid inline styles while keeping your UI fully dynamic.

This project is a modernised ES module version of the original CoffeeScript implementation.

For live examples and backstory, see https://vegetalope.com/build/dyss/.

Documentation: Read the latest published docs at https://vegetalope.com/build/dyss/docs/. The source is also documented with JSDoc, so your editor will still show parameter types, return types, and examples on hover.


Install from npm

npm install dyss

Basic example

import Sheet from 'dyss'

const sheet = new Sheet()

sheet.add('.box', {
	width: '120px',
	height: '120px',
	backgroundColor: 'red',
	position: 'absolute',
	top: '40px',
	left: '40px'
})

This creates a real stylesheet and inserts a CSS rule for .box.

If you want a constructable stylesheet that is also registered in document.adoptedStyleSheets, use:

const constructedSheet = new Sheet({ mode: 'constructed' })

Create a dynamic class

You can generate a unique class name and reuse it later.

const className = sheet.addClass({
	padding: '16px',
	backgroundColor: '#1f2937',
	color: 'white',
	borderRadius: '12px'
})

// Apply it to any element
element.classList.add(className)

Update an existing rule

sheet.updateSet(`.${className}`, {
	backgroundColor: '#2563eb',
	borderRadius: '24px'
})

Only the rule inside the stylesheet is modified, not the element styles.


API

Quick reference based on the published docs. The current public surface is 15 items total: 2 instance properties and 13 public methods.

sheet.mode

Stores the active creation mode for the instance.

  • Starts as style-tag by default unless you pass a different mode to the constructor.
  • After destroy(), dyss sets this property to null.

sheet.sheet

Holds the underlying native stylesheet object used for rule insertion and lookup.

  • This is the same object returned by getSheet().
  • After destroy(), dyss clears the property and sets it to null.

new Sheet(options?: { mode?: 'style-tag' | 'constructed' })

Creates a stylesheet instance in the browser and stores the underlying CSSStyleSheet on the instance.

  • style-tag is the default and injects a real <style> element into document.head.
  • constructed uses new CSSStyleSheet() and appends it to document.adoptedStyleSheets.
  • Constructed mode throws if the current browser does not support constructable stylesheets.
import Sheet from 'dyss'

const sheet = new Sheet()
const adopted = new Sheet({ mode: 'constructed' })

sheet.addMediaAttribute(mediaAttribute)

Sets the media attribute on the backing <style> tag.

  • Only available in style-tag mode.
  • Useful when the entire stylesheet should apply only to print or a single media query.
const sheet = new Sheet()

sheet.addMediaAttribute('(max-width: 60rem)')

sheet.getSheet()

Returns the underlying native CSSStyleSheet instance.

const nativeSheet = sheet.getSheet()

if (nativeSheet) {
	console.log(nativeSheet.cssRules.length)
}

sheet.add(selector, set, index?)

Inserts a CSS rule for a selector using an object of camelCase style declarations.

  • Property keys should follow the same naming style as element.style, such as backgroundColor.
  • If index is omitted, the rule is appended to the end of the stylesheet.
sheet.add('.card', {
	padding: '1rem',
	backgroundColor: '#111827',
	color: '#ffffff'
})

sheet.add('.card--first', { order: '0' }, 0)

sheet.addClass(set)

Generates a random class name, inserts a rule for it, and returns the class name without a leading dot.

  • The returned value is intended for element.classList.add(...).
  • Internally, dyss prefixes the generated name with . before inserting the rule.
const pillClass = sheet.addClass({
	padding: '0.4rem 0.7rem',
	borderRadius: '999px',
	backgroundColor: '#c21f2b',
	color: '#ffffff'
})

button.classList.add(pillClass)

sheet.updateSet(selector, set)

Merges declarations into an existing rule, or creates the rule if it does not exist yet.

  • This preserves existing properties that are not mentioned in the new set.
  • Values ending in !important are applied with style.setProperty(..., 'important').
sheet.updateSet('.card', {
	backgroundColor: '#2563eb',
	borderRadius: '1rem',
	color: '#ffffff !important'
})

sheet.replaceSet(selector, set)

Removes every existing declaration from a rule, then applies the new set.

  • This is a full replacement, not a merge.
  • If the selector is missing, dyss creates a new rule first.
sheet.replaceSet('.card', {
	display: 'grid',
	gap: '0.75rem'
})

sheet.remove(selector)

Deletes the matching rule from the stylesheet.

  • The lookup includes top-level rules and rules nested inside @media blocks.
sheet.remove('.card')

sheet.removeClass(className)

Deletes a class rule using either the raw class name or the dotted selector form.

  • Passing badge and .badge both target the same .badge rule.
const badgeClass = sheet.addClass({ color: '#ffffff' })

sheet.removeClass(badgeClass)
sheet.removeClass('.legacy-badge')

sheet.destroy()

Cleans up the stylesheet and clears the instance references.

  • In style-tag mode, dyss removes the injected <style> element from the DOM.
  • In constructed mode, dyss removes the sheet from document.adoptedStyleSheets.
const sheet = new Sheet()

sheet.add('.toast', { opacity: '1' })

// later, during teardown
sheet.destroy()

sheet.addMedia(mediaQuery, selector, set)

Adds a selector rule inside an @media block, creating the media block on first use.

  • Reuses an existing @media rule when the same media query string is used again.
  • Rules inside the block are appended in insertion order.
sheet.addMedia('(max-width: 48rem)', '.card', {
	padding: '0.75rem',
	fontSize: '0.95rem'
})

sheet.addPseudo(selector, pseudo, set)

Adds a rule for a pseudo-class or pseudo-element.

  • The pseudo argument may be passed as hover or :hover.
  • Pseudo-elements such as ::before also work.
sheet.addPseudo('.button', ':hover', {
	backgroundColor: '#1a2747',
	color: '#ffffff'
})

sheet.addPseudo('.button', '::before', {
	content: '""',
	display: 'block'
})

sheet.get(selector)

Returns the matching CSSStyleRule, or null when no rule matches.

  • Like remove(), this searches top-level rules and rules nested inside media queries.
  • Once you have the rule, you can inspect rule.style, rule.cssText, and other CSSOM properties.
const rule = sheet.get('.card')

if (rule) {
	console.log(rule.style.backgroundColor)
}

Running the Example Locally (Modern JS/ESM Approach)

To use ES modules in the browser, your files must be served over HTTP(S)—directly opening HTML files via file:// does not support ESM in modern browsers.

We recommend using a minimal JS-friendly dev server. Here are two common ways:

Option 1: Using vite (recommended for JS projects)

npm create vite@latest  # or, if already initialized: npm install vite --save-dev
npx vite --root=example

Then open:

http://localhost:5173/

Tip: You can use other modern dev servers like serve, http-server, etc. Pick whichever suits your stack.


Build and minify

This project uses esbuild.

Install it:

npm install --save-dev esbuild

Build and minify:

npx esbuild src/dyss.js --bundle --minify --format=esm --target=es2019 --outfile=dist/dyss.min.js

Browser support

style-tag mode works in modern evergreen browsers.

constructed mode requires document.adoptedStyleSheets and constructable CSSStyleSheet support.