A generic, accessible React component library with dark/light theme support.
Built with React 19, TypeScript, SCSS Modules, and documented with Storybook 10.
- WCAG 2.2 AA compliant — enforced via
eslint-plugin-jsx-a11yand@storybook/addon-a11y(axe-core) - Screen-reader friendly — proper ARIA attributes, semantic HTML, and
VisuallyHiddenutility - Dark & light mode — CSS custom properties with
data-themeattribute switching - Mobile-first — responsive breakpoints using
min-widthmedia queries - Modern browser support — Chrome, Edge, Firefox, Safari (last 2 versions)
- Tree-shakeable — ESM and CJS output with per-component imports
- Fully typed — TypeScript declarations included
- Node.js >=20.19.0 or >=22.12.0
- npm >=10
npm install @pigna/component-library// Import components
import { Button } from '@pigna/component-library';
// Import global styles (reset + design tokens) — opt-in, do this once in your app entry
import '@pigna/component-library/styles';
function App() {
return (
<Button variant="primary" size="md" onClick={() => alert('Clicked!')}>
Click me
</Button>
);
}The library supports three theming modes:
1. Automatic (OS preference) — Works out of the box. If the user's OS is set to dark mode, components render in dark mode automatically.
2. Manual override — Set data-theme on <html> to force a specific theme:
<html data-theme="dark" lang="en-GB"> <!-- Force dark -->
<html data-theme="light" lang="en-GB"> <!-- Force light -->3. JavaScript toggle:
// Force dark
document.documentElement.setAttribute('data-theme', 'dark');
// Force light
document.documentElement.setAttribute('data-theme', 'light');
// Follow OS preference (remove override)
document.documentElement.removeAttribute('data-theme');git clone https://github.com/Pigna/Component-Library.git
cd Component-Library
npm installnpm run devOpens Storybook at http://localhost:6006.
npm run buildOutputs ESM, CJS, and type declarations to dist/.
npm run test # single run
npm run test:watch # watch modenpm run lint # ESLint (TypeScript + accessibility)
npm run lint:styles # Stylelint (SCSS)
npm run format # PrettierEach component lives in its own folder under src/components/:
src/components/Button/
├── Button.tsx # Component with typed props and JSDoc
├── Button.module.scss # Scoped styles using CSS custom properties
├── Button.stories.tsx # Storybook stories with controls
├── Button.test.tsx # Vitest + Testing Library tests
└── index.ts # Named re-export
Then re-export from src/index.ts:
export { Button } from './components/Button';
export type { ButtonProps } from './components/Button';| Script | Description |
|---|---|
npm run dev |
Start Storybook dev server on port 6006 |
npm run build |
Build the library (ESM + CJS + types) |
npm run build:storybook |
Build static Storybook site |
npm run test |
Run tests once |
npm run test:watch |
Run tests in watch mode |
npm run lint |
Lint TypeScript with ESLint + a11y rules |
npm run lint:fix |
Lint and auto-fix |
npm run lint:styles |
Lint SCSS with Stylelint |
npm run format |
Format code with Prettier |
npm run format:check |
Check formatting without writing |
This project uses GitHub Actions for continuous integration and publishing.
Runs automatically on every push to main and on pull requests targeting main. It runs lint, tests, and build to catch issues early.
Runs when you push a version tag (e.g. v0.2.0). The version in package.json is set automatically from the tag name — no need to update it manually. The workflow will:
- Lint, test, and build the library
- Publish the package to GitHub Packages
- Create a GitHub Release with a consumer-ready ZIP (
pigna-component-library-<version>.zip) containingdist/,package.json,README.md, andLICENSE
Note: The repo
README.mdis for contributors. The consumer-facing readme lives inPACKAGE.mdand is copied into the npm package and release ZIP at publish time.
To publish a new version:
git tag v0.2.0
git push origin v0.2.0Since this package is hosted on GitHub Packages, the consuming project needs a one-time setup.
Go to GitHub → Settings → Developer settings → Personal access tokens and create a classic token with the read:packages scope.
@pigna:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${NPM_TOKEN}Do not commit a real token. The
.npmrcreferences an environment variable (NPM_TOKEN).
-
Locally: export the token in your shell before running
npm install:export NPM_TOKEN=ghp_your_token_here # macOS/Linux $env:NPM_TOKEN="ghp_your_token_here" # PowerShell
Alternatively, add the token to your user-level
~/.npmrcso it applies globally without polluting the project. -
In CI: add
NPM_TOKENas a repository secret in the consuming project's GitHub settings. Then pass it as an environment variable in your workflow.
npm install @pigna/component-librarynpx skills add pbakaus/impeccable- Styling tool by pbakaus/impeccable https://impeccable.style/
MIT