React Component Library
Build a production-ready React component library with Bunup in minutes. Zero config. Just works.
Quick Start
Scaffold a minimal starter or publish-ready React component library in seconds:
bunx @bunup/cli@latest create
Select React Component Library from the options. Now you're ready to build components.
Creating Components
Create your first component:
export function Button(props: React.ComponentProps<'button'>): React.ReactNode {
return <button type="button" {...props} />
}
Export it from your entry point:
export { Button } from './components/button'
Build it:
bunx bunup
Your component is now compiled in dist/index.js
with TypeScript declarations in dist/index.d.ts
.
Styling Options
Bunup supports multiple styling approaches out of the box. Choose what works best for your library.
Pure CSS
Import CSS directly in your components. Bunup bundles everything automatically.
[data-slot="button"] {
background: hsl(211, 100%, 50%);
color: white;
padding: 0.6rem 1.2rem;
border: none;
border-radius: 0.5rem;
cursor: pointer;
}
[data-slot="button"]:hover {
background: hsl(211, 100%, 45%);
}
export function Button(props: React.ComponentProps<'button'>): React.ReactNode {
return <button type="button" data-slot="button" {...props} />
}
import './styles.css'
export { Button } from './components/button'
Your CSS is automatically bundled into dist/index.css
with cross-browser compatibility. Learn more about CSS support.
CSS Modules
Get automatic class name scoping with CSS modules. Just use .module.css
:
.button {
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
color: white;
}
.primary {
background-color: #007bff;
}
.primary:hover {
background-color: #0056b3;
}
import styles from './button.module.css'
export function Button(props: React.ComponentProps<'button'>): React.ReactNode {
return (
<button
type="button"
className={`${styles.button} ${styles.primary}`}
{...props}
/>
)
}
TypeScript definitions are generated automatically - you get full autocomplete and type safety. Learn more about CSS modules.
Tailwind CSS
Use Tailwind CSS v4 with zero PostCSS configuration. Your components work everywhere - consumers don't need Tailwind installed.
Install the Tailwind CSS plugin:
bun add --dev @bunup/plugin-tailwindcss
Add it to your config:
import { defineConfig } from 'bunup'
import { tailwindcss } from '@bunup/plugin-tailwindcss'
export default defineConfig({
plugins: [tailwindcss()],
})
Create your styles with a scoped prefix to prevent conflicts:
@import "tailwindcss" prefix(mylib);
Use prefixed classes in your components:
export function Button(props: React.ComponentProps<'button'>): React.ReactNode {
return (
<button
type="button"
className="mylib:bg-blue-500 mylib:hover:bg-blue-600 mylib:text-white mylib:px-4 mylib:py-2 mylib:rounded-md"
{...props}
/>
)
}
import './styles.css'
export { Button } from './components/button'
The plugin outputs scoped, tree-shaken CSS. Only the classes you use are included, and the prefix prevents conflicts with consumer applications. Learn more about the Tailwind CSS plugin.
Distribution
Configure your package.json
for npm publishing:
{
"name": "my-component-library",
"version": "1.0.0",
"type": "module",
"files": [
"dist"
],
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"./styles.css": "./dist/index.css",
"./package.json": "./package.json"
},
"peerDependencies": {
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
}
}
Consumers import your library like this:
import 'my-component-library/styles.css'
import { Button } from 'my-component-library'
function App() {
return <Button>Click me</Button>
}
Inject Styles Optional
Want to skip the separate CSS import? Use the inject styles option to bundle CSS directly into JavaScript:
bunup --css.inject
import { defineConfig } from 'bunup'
export default defineConfig({
css: {
inject: true,
},
})
Or with the Tailwind CSS plugin:
import { defineConfig } from 'bunup'
import { tailwindcss } from '@bunup/plugin-tailwindcss'
export default defineConfig({
plugins: [
tailwindcss({
inject: true,
})
],
})
Now consumers only need to import your components:
import { Button } from 'my-component-library'
function App() {
return <Button>Click me</Button>
}
Styles are automatically injected at runtime.
Examples
Check out complete examples in the examples directory: