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

@helal_aytah/classname_builder

v1.0.16

Published

Headless, zero-dependency TypeScript className builder for the web. Accepts strings, nested arrays and conditional object maps, preserves insertion order and returns a deduplicated space-separated class string. Exports both ESM and CJS builds.

Downloads

40

Readme

@helal_aytah/classname_builder

npm version npm downloads License: MIT CI Status Checked with Biome

A headless, zero-dependency TypeScript className builder for the web. It accepts strings, nested arrays, and conditional object maps, returning a deduplicated, space-separated class string. It's built to be robust, lightweight, and easy to integrate into any modern web project.

This utility is perfect for component-based frameworks like React, Next.js, Vue, or Svelte, even vanilla javascript where dynamic and conditional class names are a common requirement.

Features

  • Tiny & Zero-Dependency: Adds minimal overhead to your project.
  • Fully Typed: Written in TypeScript for superior autocompletion and type safety.
  • Flexible API: Effortlessly handles strings, objects, arrays, and any nested combination.
  • Smart Deduplication: Automatically removes duplicate class names.
  • Modern Module Support: Exports both ESM (import) and CJS (require) builds.
  • Falsy Handling: Intelligently ignores null, undefined, and false to simplify conditional logic.

Installation

Install the package using your favorite package manager:

# Using npm
npm install @helal_aytah/classname_builder

# Using yarn
yarn add @helal_aytah/classname_builder

# Using pnpm
pnpm add @helal_aytah/classname_builder

Usage Examples

1. ES Modules (React, Vue, Svelte, etc.)

This is the most common use case in modern frontend development.

import { classNameBuilder } from "@helal_aytah/classname_builder";

const MyButton = ({ isPrimary, isActive, children }) => {
  const classes = classNameBuilder("btn", isPrimary && "btn-primary", {
    active: isActive,
    disabled: !isActive,
  });

  // If isPrimary=true and isActive=true, classes will be: "btn btn-primary active"
  // If isPrimary=false and isActive=false, classes will be: "btn disabled"

  return <button className={classes}>{children}</button>;
};

2. CommonJS (Node.js / Legacy Build Systems)

For environments that use the require syntax, the package works out of the box.

// In a file like `server-component.js` or a script running in Node.js
const { classNameBuilder } = require("@helal_aytah/classname_builder");

// --- Example 1: Basic usage ---
const buttonClasses = classNameBuilder("btn", "btn-large", "btn-primary");
console.log(buttonClasses);
// Output: "btn btn-large btn-primary"

// --- Example 2: Conditional classes ---
const isLoggedIn = false;
const hasError = true;

const userStatusClasses = classNameBuilder({
  "status-online": isLoggedIn,
  "status-offline": !isLoggedIn,
  "has-error": hasError,
});
console.log(userStatusClasses);
// Output: "status-offline has-error"

// --- Example 3: Mixed array ---
const cardClasses = classNameBuilder(
  "card",
  ["card-body", { "shadow-lg": true, rounded: false }],
  isLoggedIn ? "user-card" : null,
);
console.log(cardClasses);
// Output: "card card-body shadow-lg"

3. Vanilla JS (Directly in the Browser)

You can use the library directly in an HTML file by including a UMD (Universal Module Definition) build. This is useful for demos, prototyping, or legacy projects.

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vanilla JS ES Module Example</title>
    <style>
      body {
        font-family: sans-serif;
      }
      .btn {
        padding: 10px 20px;
        border: 1px solid #ccc;
        border-radius: 5px;
        cursor: pointer;
        transition: all 0.2s ease-in-out;
      }
      .btn-primary {
        background-color: #007bff;
        color: white;
        border-color: #007bff;
      }
      .active {
        box-shadow: 0 0 8px rgba(0, 123, 255, 0.8);
        transform: scale(1.05);
      }
      .disabled {
        opacity: 0.5;
        cursor: not-allowed;
      }
    </style>
  </head>
  <body>
    <h1>Vanilla JS ClassName Builder (from CDN)</h1>
    <button id="myButton">Click Me</button>
    <p>Current classes: <code id="class-display"></code></p>

    <!-- 
      The script tag now has type="module".
      This allows us to use the 'import' keyword directly in the browser.
    -->
    <script type="module">
      // Import the function directly from the JSDelivr CDN URL
      import { classNameBuilder } from "https://cdn.jsdelivr.net/npm/@helal_aytah/classname_builder/dist/index.js";

      const button = document.getElementById("myButton");
      const classDisplay = document.getElementById("class-display");

      let isActive = true;
      let isPrimary = true;

      function updateButtonClasses() {
        const classes = classNameBuilder("btn", {
          "btn-primary": isPrimary,
          active: isActive,
          disabled: !isActive, // Add a disabled class when not active
        });

        // Apply the generated classes to the button element
        button.className = classes;

        // Display the current class string
        classDisplay.textContent = `"${classes}"`;
      }

      // Set the initial state of the button
      updateButtonClasses();

      // Add a click event listener to toggle the button's state
      button.addEventListener("click", () => {
        isActive = !isActive; // Toggle the active state
        updateButtonClasses();
      });
    </script>
  </body>
</html>

API Reference

The package exports a primary function classNameBuilder, a ClassNameBuilder class, and the TClassNameValue type.

classNameBuilder(...args)

This is the main function you'll use. It's a convenience wrapper around ClassNameBuilder.build.

  • Parameters: ...args: TClassNameValue[] — A spread of values to be processed.
  • Returns: string | undefined — A space-separated string of unique class names, or undefined if no valid classes are generated.

The TClassNameValue type can be any of the following:

| Type | Description | Example | | ------------------------------ | -------------------------------------------------------------------------------- | --------------------------------------------- | | string | A single class or multiple space-separated classes. | 'btn btn-primary' | | object | A map where keys are class names and truthy values cause the key to be included. | { active: true, 'text-red': hasError } | | Array<TClassNameValue> | An array containing any valid TClassNameValue type. Arrays can be nested. | ['base', { conditional: true }, ['nested']] | | null \| undefined \| boolean | Falsy values that are ignored, allowing for simple inline conditionals. | isLoggedIn && 'user-active' |


Development Scripts

This project uses pnpm as its package manager and includes several scripts for development:

  • pnpm dev: Run Vitest in watch mode for continuous testing.
  • pnpm test: Run the full test suite once.
  • pnpm lint: Lint and format the codebase.
  • pnpm bench: Run benchmark tests.
  • pnpm coverage: Generate a test coverage report.
  • pnpm build: Create a production-ready build in the dist/ folder.
  • pnpm ci: Run the full continuous integration pipeline (lint, test, build).

Contributing

Contributions are welcome! If you have a feature request, bug report, or want to improve the code, please follow these steps:

  1. Fork the repository on GitHub.
  2. Clone your fork to your local machine.
  3. Create a new branch for your changes: git checkout -b my-feature-branch.
  4. Make your changes and commit them with a clear message.
  5. Push your branch to your fork on GitHub.
  6. Open a Pull Request to the main repository.

Please ensure your code adheres to the existing style and that the pnpm ci command passes successfully.

License

This project is licensed under the MIT License. See the LICENSE file for details.

Author