https://github.com/webneat/react-dye
A simple way to add CSS classes to React components.
https://github.com/webneat/react-dye
css library reactjs style ui-components
Last synced: about 1 year ago
JSON representation
A simple way to add CSS classes to React components.
- Host: GitHub
- URL: https://github.com/webneat/react-dye
- Owner: webNeat
- Created: 2019-02-27T23:33:31.000Z (over 7 years ago)
- Default Branch: main
- Last Pushed: 2025-04-04T14:21:24.000Z (about 1 year ago)
- Last Synced: 2025-04-10T15:09:42.437Z (about 1 year ago)
- Topics: css, library, reactjs, style, ui-components
- Language: TypeScript
- Size: 545 KB
- Stars: 5
- Watchers: 2
- Forks: 2
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# react-dye
A simple way to style React components.
[](https://bundlephobia.com/result?p=react-dye)
[](https://www.npmjs.com/package/react-dye)
[](https://github.com/webneat/react-dye/actions?query=branch%3Amain)
[](LICENSE)
## Contents
- [Quick Usage](#quick-usage)
- [Features](#features)
- [Documentation](#documentation)
- [Using `dye` to style HTML elements](#using-dye-to-style-html-elements)
- [Defining variants](#defining-variants)
- [Applying the same styles to a different HTML element](#applying-the-same-styles-to-a-different-html-element)
- [Extending classes and variants of a component](#extending-classes-and-variants-of-a-component)
- [Creating a new `dye` function with custom config](#creating-a-new-dye-function-with-custom-config)
- [Merging TailwindCSS classes without conflict](#merging-tailwindcss-classes-without-conflict)
- [Contributing](#contributing)
- [Changelog](#changelog)
## Quick Usage
```bash
npm install react-dye
```
```tsx
import { dye } from 'react-dye'
// Create a styled button with a danger variant
const Button = dye('px-4 py-2 rounded font-medium', {
default: 'bg-blue-500 hover:bg-blue-600',
danger: 'bg-red-500 hover:bg-red-600'
}, 'button')
// Apply the same styles to a link
const ButtonLink = Button.as('a')
// Extend with additional classes and variants
const BigButton = Button.extend('text-3xl', {
success: 'bg-green-500 hover:bg-green-600',
})
// Use as normal component
function App() {
return (
Primary Action {/* applies `default` variant by default */}
Danger Action
Big Danger!
Link {/* has the same props as the base element */}
)
}
```
## Features
- Zero dependencies.
- Lightweight (about **0.5kb** gzipped).
- Create styled components with CSS classes (ideal when using TailwindCSS or similar).
- Use variants to create different styles for the same component.
- Extend existing components with additional classes/variants.
- Clone components with different element.
- Returns fully typed components.
## Documentation
This library exports two functions:
- `dye`: creates a styled component with CSS classes and variants.
- `create_dye`: creates a new `dye` function with custom config.
### Using `dye` to style HTML elements
In its simplest form, `dye` takes some CSS classes and an HTML tag, and returns a component that applies the CSS classes to the element.
```tsx
import { dye } from 'react-dye'
const Title = dye('mb-2 text-2xl', 'h1')
content
```
will render
```html
content
```
The `tag` is optional, and it defaults to `div`.
```tsx
const Section = dye('p-3 mb-4')
content
```
will render
```html
content
```
You can pass additional CSS classes to the component using `className` and they will be added
```tsx
const Section = dye('p-3 mb-4')
content
```
will render
```html
content
```
**Note that by default `dye` will simply concatenate classes, if you are using TailwindCSS then check the [Merging TailwindCSS classes without conflict](#merging-tailwindcss-classes-without-conflict) guide below.**
### Defining variants
Sometimes you need to style a component differently depending on the state of the component. You can achieve this by passing an object as the second argument to `dye`, where the keys are the variants and the values are the CSS classes.
```tsx
const Button = dye('px-4 py-2 rounded', {
default: 'bg-blue-500 hover:bg-blue-600',
success: 'bg-green-500 hover:bg-green-600',
danger: 'bg-red-500 hover:bg-red-600',
}, 'button')
Default Button
Success Button
Danger Button
```
will render
```html
Default Button
Success Button
Danger Button
```
When the `variant` property is passed to the component, the corresponding classes are added to the element.
Note that the `default` variant is applied by default if defined.
### Applying the same styles to a different HTML element
What if you styled an elememt, like the `Button` above, and you want to apply the same styles to a different element? instead of duplicating the code, all components created by `dye` have a method `as()` that you can use to clone the component with a different tag.
```tsx
import {dye} from 'react-dye'
const Button = dye('px-4 py-2 rounded', {
default: 'bg-blue-500 hover:bg-blue-600',
success: 'bg-green-500 hover:bg-green-600',
danger: 'bg-red-500 hover:bg-red-600',
}, 'button')
const ButtonLink = Button.as('a') // returns a new component that renders `a` instead of `button`
Link
```
will render
```html
Link
```
### Extending classes and variants of a component
Same as `.as()`, you may need to clone a styled component but with additional classes and/or variants. You can do that with the `.extend()` method.
```tsx
import {dye} from 'react-dye'
const Button = dye('px-4 py-2 rounded', {
default: 'bg-blue-500 hover:bg-blue-600',
success: 'bg-green-500 hover:bg-green-600',
danger: 'bg-red-500 hover:bg-red-600',
}, 'button')
const BigButton = Button.extend('text-3xl font-semibold') // adds new classes
const SpecialButton = Button.extend('', {
bonus: 'bg-orange-500 hover:bg-orange-600', // adds new variant
success: 'border-2 border-green-300', // adds classes to existing variant
})
Stop
Bonus
Congratulations
```
will render
```html
Stop
Bonus
Congratulations
```
**Note that:**
- The additional classes are added to the existing classes.
- When extending an existing variant, the additional classes are added to the old ones.
if you are using TailwindCSS and want to avoid class conflicts then check the [Merging TailwindCSS classes without conflict](#merging-tailwindcss-classes-without-conflict) guide below.
### Creating a new `dye` function with custom config
if you don't like some default behavior of `dye` and want to customize things, you can use the `create_dye` function. This function takes a config object and returns a new `dye` function that you can use like the default one.
The config has the following type:
```ts
type Config = {
mergeClasses: (classes: ClassValue[]) => string
}
type ClassValue = string | undefined | null | false
```
- `mergeClasses` the function to use to filter out falsy classnames and merge the rest. The default implementation just joins the classes with a space.
That's all it's on the config now, if you see other behaviors/flags to add, please let me know :)
Check a pratical example of using `create_dye` in the [Merging TailwindCSS classes without conflict](#merging-tailwindcss-classes-without-conflict) guide below.
## Merging TailwindCSS classes without conflict
When using TailwindCSS, you probably want to avoid conflicts, simply concatenating classenames will not work. So follow the next steps:
1. Add [tailwind-merge](https://github.com/tailwindlabs/tailwind-merge) to your project
```
npm install tailwind-merge
```
2. Create a custom `dye` function that uses `twMerge` from `tailwind-merge`:
```ts
import { create_dye } from 'react-dye'
import { twMerge } from 'tailwind-merge'
export const dye = create_dye({ mergeClasses: twMerge })
```
3. Use the `dye` function exported above instead of the default one.
That's all.
Now you may have the following question: _Why not just include `tailwind-merge` as a dependency and use `twMerge` by default?_
I decided not to include it because:
- I would like this library to be generic, works with any collection of CSS classes. I don't want to tie it to TailwindCSS.
- `tailwind-merge` is great, but it would multiply the bundle size by **16**! (8kb vs 0.5kb).
## Contributing
You can contribute to this library in many ways, including:
- **Reporting bugs**: Simply open an issue and describe the bug. Please include a code snippet to reproduce the bug, it really helps to solve the problem quickly.
- **Suggesting new features**: If you have a common use case that you think worth adding to the library, open an issue and we will discuss it. Do you already have an implementation for it? Great, make a pull request and I will review it.
Those are just examples, any issue or pull request is welcome :)
## Changelog
Check out the [changelog](https://github.com/webneat/react-dye/blob/main/CHANGELOG.md) for more information.