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

reso-ui

v3.0.0

Published

Reusable React components in Typescript

Readme

Reso UI

A React component library built with TypeScript + SCSS. Ships as tree-shakeable ESM + CJS output via Rollup.

Storybook: reso-ui-storybook.s3-website-ap-southeast-1.amazonaws.com


Guiding Principles

  1. Customizability-first — Clients can and should be able to override most if not all units of a UI component. Override the entire palette via <ResoUiProvider theme={...}>, or override colours and behaviour directly on individual components via props. Clients should NOT override styles by hacky CSS means (e.g. directly overwriting compiled CSS class names in their projects).

  2. Clean and minimalistic — We eliminate clutter and prioritize ease of interaction for app users AND ease of component use for developers. Maximum configurability, yet minimal complication. Easy. Simple. Minimal.

  3. In-house solutions — We build everything ourselves (drag and drop, date selector calculations, etc). No dependencies on third-party component libraries unless absolutely necessary.

  4. Performant and zero runtime cost — Theming via CSS custom properties; no theme object traversal at render time.


Table of Contents


Using the Library (Client Setup)

Requirements

  • Node 18+
  • React ^18.2
  • React Dom ^18.2
  • classnames ^2.3 (peer dependency — install it if your project doesn't already have it)

Install

npm install reso-ui
# peer deps (if not already installed)
npm install classnames

For the latest alpha (v3 pre-release):

npm install reso-ui@alpha

For the latest stable v2 release:

npm install [email protected]

Client project files

custom.d.ts (project root)

Create this file so TypeScript knows how to handle SVG and font file imports:

// custom.d.ts
declare module "*.svg" {
  import React from "react";
  const SVG: React.FunctionComponent<React.SVGAttributes<SVGElement>>;
  export default SVG;
}

declare module "*.ttf" {
  const content: string;
  export default content;
}

Then add it to your tsconfig.json:

{
  "compilerOptions": { ... },
  "include": ["src", "custom.d.ts"]
}

Bundler Setup

The library ships pre-compiled JS (ESM + CJS), a single CSS file, and the Poppins and DancingScript font files — all locally bundled with no external network dependency.

Pick the section that matches your bundler:


Vite

Tested with Vite 6.x (@vitejs/plugin-react 5.x).

Vite handles CSS imports and font asset resolution out of the box. No vite.config.ts changes are required for reso-ui to work.

Install the core Vite dependencies:

npm install -D vite@^6.4.2 @vitejs/plugin-react@^5.2.0

If your project uses its own SCSS files, install the sass package:

npm install -D sass@^1.87.0

If your project imports .svg files as React components, add vite-plugin-svgr:

npm install -D vite-plugin-svgr@^5.2.0
// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import svgr from "vite-plugin-svgr";

export default defineConfig({
  plugins: [react(), svgr()],
});

That's it — import "reso-ui/styles" works immediately since Vite natively processes CSS from node_modules and resolves the relative url(fonts/...) paths in the stylesheet.


Webpack

Tested with Webpack 5.x (matches the Reso online-store and web-storefront projects).

Your webpack config needs:

  1. CSS loader — to handle import "reso-ui/styles"
  2. asset modules — to resolve the .ttf font files referenced in the library CSS

Install the required loaders:

npm install -D webpack@^5.99.6 webpack-cli@^6.0.1 webpack-dev-server@^5.2.1 \
  ts-loader@^9.5.2 style-loader@^4.0.0 css-loader@^7.1.2 \
  sass-loader@^16.0.5 sass@^1.87.0 \
  html-webpack-plugin@^5.6.3

Minimum webpack rules:

// webpack.config.js
module.exports = {
  module: {
    rules: [
      // Handle CSS (from reso-ui and your own styles)
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
      // Handle SCSS (your own styles only — reso-ui ships pre-compiled CSS)
      {
        test: /\.scss$/,
        use: ["style-loader", "css-loader", "sass-loader"],
      },
      // Required: resolve font files bundled with reso-ui
      {
        test: /\.(ttf|woff|woff2|eot)$/,
        type: "asset/resource",
      },
      // TypeScript
      {
        test: /\.tsx?$/,
        loader: "ts-loader",
        exclude: /node_modules/,
      },
    ],
  },
  resolve: {
    extensions: [".tsx", ".ts", ".js"],
  },
};

Fonts: Poppins (all weights) and DancingScript are bundled inside the npm package under dist/fonts/. The asset/resource webpack rule lets webpack resolve the font paths from dist/styles.css automatically — no CDN or manual font installation required.


Next.js

Tested with Next.js 15.x (App Router and Pages Router).

Next.js handles CSS imports, font asset resolution, and TypeScript out of the box. No next.config changes are required for reso-ui to work.

npm install next@^15.5.18 react@^18.2.0 react-dom@^18.2.0
npm install reso-ui classnames

If your project uses its own SCSS files:

npm install -D sass@^1.87.0

If your project imports .svg files as React components, configure @svgr/webpack in next.config:

// next.config.mjs
const nextConfig = {
  webpack(config) {
    config.module.rules.push({
      test: /\.svg$/,
      use: ["@svgr/webpack"],
    });
    return config;
  },
};

export default nextConfig;
npm install -D @svgr/webpack@^8.1.0
App Router setup

Reso UI components use React context and hooks internally, so they require a "use client" boundary. Create a client-side provider wrapper:

// src/providers/ResoUiClientProvider.tsx
"use client";

import { ResoUiProvider } from "reso-ui";

export const ResoUiClientProvider = ({ children }: { children: React.ReactNode }) => (
  <ResoUiProvider mode="system">
    {children}
  </ResoUiProvider>
);

Then import the styles and provider in your root layout:

// src/app/layout.tsx
import "reso-ui/styles";
import "./globals.css";
import { ResoUiClientProvider } from "@/providers/ResoUiClientProvider";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <ResoUiClientProvider>
          {children}
        </ResoUiClientProvider>
      </body>
    </html>
  );
}

Use reso-ui components in any Client Component:

// src/app/dashboard/page.tsx
"use client";

import { Button, Text, View } from "reso-ui";

export default function DashboardPage() {
  return (
    <View pt={9} ph={4}>
      <Text Element="h1">Dashboard</Text>
      <Button text="Click me" onClick={() => alert("clicked")} />
    </View>
  );
}
Pages Router setup

Import styles and wrap with the provider in _app.tsx:

// pages/_app.tsx
import "reso-ui/styles";
import "../styles/globals.css";
import { ResoUiProvider } from "reso-ui";
import type { AppProps } from "next/app";

export default function App({ Component, pageProps }: AppProps) {
  return (
    <ResoUiProvider mode="system">
      <Component {...pageProps} />
    </ResoUiProvider>
  );
}

Note: Reso UI does not ship "use client" directives. In the App Router, all pages and components that use reso-ui components must be Client Components (marked with "use client"), or the reso-ui components must be wrapped in a Client Component.


Create React App (CRA)

Tested with react-scripts 5.x.

CRA handles CSS imports, font asset resolution, and SVG imports out of the box. No configuration changes are required.

npx create-react-app my-app --template typescript
cd my-app
npm install reso-ui classnames

If your project uses its own SCSS files, install the sass package:

npm install -D sass@^1.87.0

Everything else works immediately — CRA's built-in webpack config already includes CSS loaders, asset modules for fonts, and @svgr/webpack for SVG imports.


Provider setup

Wrap your application root with ResoUiProvider. It provides theming and responsive context to all Reso UI components.

// index.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { ResoUiProvider } from "reso-ui";
import "reso-ui/styles";
import App from "./App";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <ResoUiProvider>
    <App />
  </ResoUiProvider>
);

Import styles

Import the Reso UI stylesheet before your own application styles so your custom styles can override them:

// index.tsx (or index.ts / index.js)
import "reso-ui/styles";         // ← reso-ui first
import "./index.css";            // ← your app styles after

Basic usage

import { Button, Banner, Text } from "reso-ui";

export const MyPage = () => (
  <>
    <Banner type="info" text="Welcome to My App!" />
    <Text Element="h1">Hello World</Text>
    <Button text="Click me" onClick={() => alert("clicked")} />
  </>
);

All component props and usage examples are documented in the Storybook instance.


Theming & Dark Mode Setup

Reso UI supports light mode, dark mode, and system-preference-based theming out of the box. Theme switching is controlled via the mode prop on ResoUiProvider.

Quick setup

// App.tsx
import React, { useState } from "react";
import { ResoUiProvider, useTheme } from "reso-ui";
import "reso-ui/styles";

const ThemeToggle = () => {
  const { resolvedMode, setMode } = useTheme();
  return (
    <button onClick={() => setMode(resolvedMode === "light" ? "dark" : "light")}>
      Switch to {resolvedMode === "light" ? "dark" : "light"} mode
    </button>
  );
};

const App = () => (
  <ResoUiProvider mode="system">
    <ThemeToggle />
    {/* your app */}
  </ResoUiProvider>
);

Mode options

| Mode | Behaviour | |------|-----------| | "light" (default) | Light theme applied | | "dark" | Dark theme applied | | "system" | Follows the user's OS prefers-color-scheme preference and reacts to changes in real time |

How it works

ResoUiProvider wraps your app with a ThemeProvider that sets the data-resoui-theme attribute and CSS custom properties on your #root element. All Reso UI component styles scope their dark-mode overrides to [data-resoui-theme="dark"], so switching modes is instantaneous with zero re-renders of component trees.

Using useTheme in your own components

import { useTheme } from "reso-ui";

const MyComponent = () => {
  const { resolvedMode, setMode, theme } = useTheme();
  // resolvedMode is always "light" or "dark" (resolved from "system" if needed)
  // setMode("light" | "dark" | "system") to change the theme
  // theme contains the current color and token overrides
  return <div className={resolvedMode === "dark" ? "my-dark-style" : ""}>{/* ... */}</div>;
};

Styling your own components for dark mode

Scope dark-mode overrides with the same attribute selector:

.my_component {
  background: white;
  color: #333;
}

[data-resoui-theme="dark"] .my_component {
  background: #1e1e1e;
  color: #e0e0e0;
}

Overriding the Color Palette

ResoUiProvider accepts optional theme and mode props for runtime theming with no build step required.

Light / dark mode

// Light (default)
<ResoUiProvider>…</ResoUiProvider>

// Dark
<ResoUiProvider mode="dark">…</ResoUiProvider>

// Follow OS preference (prefers-color-scheme)
<ResoUiProvider mode="system">…</ResoUiProvider>

Override palette semantics

Pass a partial theme.colors object to override semantic color roles. Keys map to CSS custom properties on --resoui-*.

<ResoUiProvider
  theme={{
    colors: {
      brandPrimary: "#1a365d",          // primary brand (navy)
      brandSecondary: "#c53030",        // secondary brand (coral/CTA)
      utilityError: "#e53e3e",
      utilitySuccess: "#276749",
    },
  }}
>
  <App />
</ResoUiProvider>

Full colors keys (ResoPaletteSemantics):

| Key | CSS variable | |-----|-------------| | brandPrimaryGhost | --resoui-brand-primary-ghost | | brandPrimaryLight | --resoui-brand-primary-light | | brandPrimaryMedium | --resoui-brand-primary-medium | | brandPrimary | --resoui-brand-primary | | brandPrimaryDark | --resoui-brand-primary-dark | | brandPrimaryDarkest | --resoui-brand-primary-darkest | | brandSecondaryPale | --resoui-brand-secondary-pale | | brandSecondaryLight | --resoui-brand-secondary-light | | brandSecondary | --resoui-brand-secondary | | brandSecondaryDark | --resoui-brand-secondary-dark | | brandSecondaryDarker | --resoui-brand-secondary-darker | | brandSecondaryGradient | --resoui-brand-secondary-gradient | | brandTertiaryPale | --resoui-brand-tertiary-pale | | brandTertiaryLight | --resoui-brand-tertiary-light | | brandTertiary | --resoui-brand-tertiary | | brandTertiaryDark | --resoui-brand-tertiary-dark | | brandTertiaryDarker | --resoui-brand-tertiary-darker | | brandQuaternaryPale | --resoui-brand-quaternary-pale | | brandQuaternaryLight | --resoui-brand-quaternary-light | | brandQuaternary | --resoui-brand-quaternary | | brandQuaternaryDark | --resoui-brand-quaternary-dark | | brandQuaternaryDarker | --resoui-brand-quaternary-darker | | utilitySuccessBg | --resoui-utility-success-bg | | utilitySuccessLight | --resoui-utility-success-light | | utilitySuccess | --resoui-utility-success | | utilitySuccessDark | --resoui-utility-success-dark | | utilityWarningBg | --resoui-utility-warning-bg | | utilityWarningLight | --resoui-utility-warning-light | | utilityWarning | --resoui-utility-warning | | utilityWarningDark | --resoui-utility-warning-dark | | utilityErrorBg | --resoui-utility-error-bg | | utilityErrorLight | --resoui-utility-error-light | | utilityError | --resoui-utility-error | | utilityErrorDark | --resoui-utility-error-dark | | utilityInfoBg | --resoui-utility-info-bg | | utilityInfoLight | --resoui-utility-info-light | | utilityInfo | --resoui-utility-info | | utilityInfoDark | --resoui-utility-info-dark | | neutralLightest | --resoui-neutral-lightest | | neutralLight | --resoui-neutral-light | | neutralMedium | --resoui-neutral-medium | | neutralDark | --resoui-neutral-dark | | neutralDarker | --resoui-neutral-darker | | neutralOverlay | --resoui-neutral-overlay | | baseWhite | --resoui-base-white | | baseBlack | --resoui-base-black |

Override spacing, typography, and layout tokens

<ResoUiProvider
  theme={{
    tokens: {
      fontFamily: "'Inter', sans-serif",
      radiusDefault: "4px",
      radiusLg: "8px",
      spacing4: "20px",
    },
  }}
>
  <App />
</ResoUiProvider>

Full tokens keys (ResoTokens):

| Key | CSS variable | Default | |-----|-------------|---------| | spacing0spacing9 | --resoui-spacing-0--resoui-spacing-9 | 0px96px | | fontFamily | --resoui-font-family | "Poppins", "Roboto", sans-serif | | fontSize1fontSize9 | --resoui-font-size-1--resoui-font-size-9 | 10px26px | | fontWeightNormal | --resoui-font-weight-normal | 400 | | fontWeightMedium | --resoui-font-weight-medium | 500 | | fontWeightSemibold | --resoui-font-weight-semibold | 600 | | fontWeightBold | --resoui-font-weight-bold | 700 | | radiusSm | --resoui-radius-sm | 4px | | radiusDefault | --resoui-radius-default | 8px | | radiusLg | --resoui-radius-lg | 16px | | radiusFull | --resoui-radius-full | 9999px | | shadowSm | --resoui-shadow-sm | 0 1px 3px rgba(0,0,0,0.1) | | shadowDefault | --resoui-shadow-default | 0px 2px 15px rgba(34,60,102,0.2) | | shadowLg | --resoui-shadow-lg | 0px 4px 25px rgba(34,60,102,0.15) | | transitionFast | --resoui-transition-fast | 0.125s | | transitionNormal | --resoui-transition-normal | 0.25s | | transitionSlow | --resoui-transition-slow | 0.5s |


Utility Classes

Reso UI ships utility CSS classes that consumer projects can apply directly via className or rootClassName. These are included in the reso-ui/styles stylesheet and support dark mode automatically where applicable.

Quick Reference

| Class | Category | Dark Mode | Description | |-------|----------|-----------|-------------| | resoui_section_border | Layout | Yes | Bordered section container with default border-radius | | resoui_table_base | Tables | Yes | Base <table> styling (font, collapse, full width) | | resoui_th_base | Tables | Yes | Table header cell (padding, border, font-weight) | | resoui_tr_base | Tables | Yes | Table row (border, hover highlight) | | resoui_tr_base_selected | Tables | Yes | Selected table row highlight | | resoui_td_base | Tables | No | Table data cell (padding) | | resoui_navItem_base | Navigation | No | Nav item base layout for custom NavItem renders | | resoui_dropdown_option_base | Forms | Yes | Dropdown option base for custom DropdownSelect options | | resoui_no_select | General | No | Disable text selection | | resoui_component_disabled | General | No | Disabled overlay with pointer-events disabled | | resoui_background_image | General | No | Background image with cover | | resoui_truncate | Text | No | Truncate text with ellipsis | | resoui_text_no_block_margin | Text | No | Remove default block margins | | resoui_text_no_inline_margin | Text | No | Remove default inline margins |

Section Border

A bordered container for card-like content sections. Apply via rootClassName on Flex or View.

import { Flex, Text } from "reso-ui";

<Flex direction="column" rootClassName="resoui_section_border" pa={5}>
  <Text Element="h3">Section Title</Text>
  <Text>Section content goes here.</Text>
</Flex>

Light mode: 1px solid neutral border + default border-radius. Dark mode: border color automatically darkens.

Tables

Base styles for native HTML <table> elements. Apply via the className attribute. Dark mode is handled automatically.

| Class | Apply to | What it does | |-------|----------|-------------| | resoui_table_base | <table> | Font-family, border-collapse, full width, font size | | resoui_th_base | <th> | Padding, bottom border, font-weight 500, left-aligned | | resoui_tr_base | <tr> | Bottom border, hover background highlight | | resoui_tr_base_selected | <tr> | Selected row highlight (combine with resoui_tr_base) | | resoui_td_base | <td> | Cell padding |

<table className="resoui_table_base">
  <thead>
    <tr>
      <th className="resoui_th_base">Name</th>
      <th className="resoui_th_base">Email</th>
      <th className="resoui_th_base">Role</th>
    </tr>
  </thead>
  <tbody>
    <tr className="resoui_tr_base">
      <td className="resoui_td_base">John Doe</td>
      <td className="resoui_td_base">[email protected]</td>
      <td className="resoui_td_base">Admin</td>
    </tr>
  </tbody>
</table>

For selected rows, combine both classes:

<tr className={`resoui_tr_base ${selectedId === item.id ? "resoui_tr_base_selected" : ""}`}>

Add custom column-specific styles alongside the utility classes:

<th className="resoui_th_base myPage_th_right">Amount</th>
<td className="resoui_td_base myPage_td_mono">$120.00</td>
.myPage_th_right { text-align: right; }
.myPage_td_mono { font-family: monospace; font-size: 12px; }

Nav Item Base

Base layout class for custom nav items rendered inside NavItem via renderCustomNavItem. Provides standard sizing consistent with the Navbar.

import { NavItem } from "reso-ui";
import { Link, useLocation } from "react-router-dom";

const AppNavItem = ({ to, children }) => {
  const { pathname } = useLocation();

  return (
    <NavItem
      renderCustomNavItem={() => (
        <Link
          to={to}
          className={`navItem_base ${pathname === to ? "my_nav_active" : ""}`}
        >
          {children}
        </Link>
      )}
    >
      {children}
    </NavItem>
  );
};

Dropdown Option Base

Base class for custom dropdown options rendered inside DropdownSelect. Provides consistent sizing, padding, and dark mode text color.

import { DropdownSelect } from "reso-ui";
import { Link } from "react-router-dom";

<DropdownSelect label="Account">
  <Link to="/profile" className="resoui_dropdown_option_base">My Profile</Link>
  <Link to="/settings" className="resoui_dropdown_option_base">Settings</Link>
</DropdownSelect>

General Utilities

| Class | What it does | |-------|-------------| | resoui_no_select | Prevent text selection (all browser prefixes) | | resoui_component_disabled | Semi-transparent overlay + disable pointer events | | resoui_background_image | Background image: cover, centered, no-repeat |

<Flex rootClassName={isLocked ? "resoui_component_disabled" : ""}>
  <Text>This section is locked</Text>
</Flex>

Text Utilities

| Class | What it does | |-------|-------------| | resoui_truncate | Truncate with ellipsis (overflow: hidden; text-overflow: ellipsis; white-space: nowrap) | | resoui_text_no_block_margin | Remove block margins from headings (margin-block-start: 0) | | resoui_text_no_inline_margin | Remove inline margins |

<Text rootClassName="resoui_truncate" rootStyles={{ maxWidth: "200px" }}>
  Very long product name that should be truncated
</Text>

Dev Notes

Available commands

| Command | What it does | |---------|-------------| | npm start | Webpack dev server → serves src/App.tsx at http://localhost:3000 | | npm run storybook | Storybook dev server at http://localhost:6006 | | npm run build | Rollup production build → dist/esm/, dist/cjs/, dist/styles.css | | npm run build-storybook | Static Storybook build → storybook-static/ | | npm test | Jest unit tests (all 65 suites) | | npm run test-coverage | Jest with coverage report → coverage/ | | npm run lint | TSLint check (excludes stories and test files) |

Viewing the App.tsx sandbox

npm start starts a Webpack dev server that hot-reloads src/App.tsx. This file is a scratchpad for manually testing components during development — it is not the library entry point.

npm start
# → http://localhost:3000

App.tsx is already wrapped with <ResoUiProvider> in src/index.tsx, so all components render with the default theme.

Running Storybook

npm run storybook
# → http://localhost:6006

Storybook is the primary UI for browsing all components, their props, and usage examples.

Library entry point

The library exports everything from src/library/index.ts. When you run npm run build, Rollup compiles this to:

dist/
  esm/          ← tree-shakeable ES modules (one file per component)
  cjs/          ← CommonJS bundle
  styles.css    ← single compiled stylesheet for all components

dist/ is not committed to git — it is built fresh in CI before every npm publish.


CI/CD Notes

The pipeline is defined in .github/workflows/ci-cd.yml.

What happens on every push / PR

  1. Lint (npm run lint)
  2. Unit tests (npm run test-coverage) on Node 18 and Node 20
  3. Library build (npm run build)
  4. Storybook build (npm run build-storybook)

PRs to main, 2.x, v3, or beta must pass all four steps.

Branch → npm dist-tag mapping

| Branch | npm dist-tag | Version format | Example | |--------|-------------|----------------|---------| | main | @latest | x.0.0 | 3.1.0 | | v3 | @alpha | 3.0.0-alpha.n | 3.0.0-alpha.5 | | beta | @beta | x.0.0-beta.n | 3.1.0-beta.2 | | 2.x | @2.x | 2.x.x | 2.44.0 |

How to make a change and publish a new version

  1. Check out main (or v3 for alpha work):

    git checkout main    # for stable releases
    # or
    git checkout v3      # for alpha pre-releases
  2. Make your changes, commit using Conventional Commits:

    git add .
    git commit -m "feat: add Tooltip component"
    # or: fix: correct Button disabled opacity
    # or: chore: update dependencies

    Commit type determines the version bump:

    • fix: → patch (3.0.1)
    • feat: → minor (3.1.0)
    • feat!: or BREAKING CHANGE: footer → major (4.0.0)
  3. Push — CI runs automatically. If all checks pass, semantic-release determines the next version, publishes to npm, and commits the updated CHANGELOG.md and package.json back to the branch.

    git push origin main
  4. Pull the release commit after CI finishes (semantic-release pushes a version bump commit back):

    git pull origin main

How to publish alpha (pre-release) versions

Work on the v3 branch. Every push that contains a fix: or feat: commit automatically publishes a new 3.0.0-alpha.n to the @alpha dist-tag.

git checkout v3
# make changes
git commit -m "feat: add Paginator component"
git push origin v3
# → publishes 3.0.0-alpha.5 to npm @alpha

Clients can install alpha builds:

npm install reso-ui@alpha

How to publish beta versions

Push to the beta branch. Follows the same Conventional Commit rules; versions are tagged @beta.

git checkout beta
git merge v3                     # merge alpha work into beta for wider testing
git push origin beta
# → publishes 3.0.0-beta.1 to npm @beta

How to create a breaking change (new major version)

Use the BREAKING CHANGE footer in your commit message or add ! after the type:

# Method 1 — exclamation mark
git commit -m "feat!: remove theme prop from all components"

# Method 2 — footer
git commit -m "feat: remove theme prop from all components

BREAKING CHANGE: The theme prop has been removed from all components.
Wrap your app in <ResoUiProvider mode=\"dark\"> instead."

When pushed to main, this bumps the major version (e.g. 3.0.04.0.0).

Before merging a major version to main, create a maintenance branch for the previous major so it can still receive patch releases:

# Preserve current main as a maintenance line before bumping major
git checkout main
git checkout -b 3.x              # create 3.x maintenance branch
git push origin 3.x
# Add "3.x" to release.config.js branches array, then push major change to main

Maintaining an older major (e.g. v2 patches)

The 2.x branch receives security fixes and critical patches without merging v3 changes.

git checkout 2.x
git commit -m "fix: correct date selector boundary validation"
git push origin 2.x
# → publishes 2.44.1 to npm @2.x

Clients pinned to v2 install patches with:

npm install [email protected]