{"id":20321339,"url":"https://github.com/webneat/react-dye","last_synced_at":"2025-04-11T19:09:26.859Z","repository":{"id":34242299,"uuid":"173006859","full_name":"webNeat/react-dye","owner":"webNeat","description":"A simple way to add CSS classes to React components.","archived":false,"fork":false,"pushed_at":"2025-04-04T14:21:24.000Z","size":558,"stargazers_count":5,"open_issues_count":1,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-10T15:09:42.437Z","etag":null,"topics":["css","library","reactjs","style","ui-components"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/webNeat.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-02-27T23:33:31.000Z","updated_at":"2025-02-20T21:37:13.000Z","dependencies_parsed_at":"2024-11-14T19:14:22.532Z","dependency_job_id":"c2f55eef-af8c-47d9-b172-9a3f74dbf8e7","html_url":"https://github.com/webNeat/react-dye","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webNeat%2Freact-dye","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webNeat%2Freact-dye/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webNeat%2Freact-dye/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webNeat%2Freact-dye/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/webNeat","download_url":"https://codeload.github.com/webNeat/react-dye/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248465325,"owners_count":21108244,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["css","library","reactjs","style","ui-components"],"created_at":"2024-11-14T19:14:04.925Z","updated_at":"2025-04-11T19:09:26.854Z","avatar_url":"https://github.com/webNeat.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# react-dye\n\nA simple way to style React components.\n\n[![Bundle size](https://img.shields.io/bundlephobia/minzip/react-dye?style=flat-square)](https://bundlephobia.com/result?p=react-dye)\n[![Version](https://img.shields.io/npm/v/react-dye?style=flat-square)](https://www.npmjs.com/package/react-dye)\n[![Tests Status](https://img.shields.io/github/actions/workflow/status/webneat/react-dye/ci.yml?branch=main\u0026style=flat-square)](https://github.com/webneat/react-dye/actions?query=branch%3Amain)\n[![MIT](https://img.shields.io/npm/l/react-dye?style=flat-square)](LICENSE)\n\n## Contents\n- [Quick Usage](#quick-usage)\n- [Features](#features)\n- [Documentation](#documentation)\n  - [Using `dye` to style HTML elements](#using-dye-to-style-html-elements)\n  - [Defining variants](#defining-variants)\n  - [Applying the same styles to a different HTML element](#applying-the-same-styles-to-a-different-html-element)\n  - [Extending classes and variants of a component](#extending-classes-and-variants-of-a-component)\n  - [Creating a new `dye` function with custom config](#creating-a-new-dye-function-with-custom-config)\n- [Merging TailwindCSS classes without conflict](#merging-tailwindcss-classes-without-conflict)\n- [Contributing](#contributing)\n- [Changelog](#changelog)\n\n## Quick Usage\n\n```bash\nnpm install react-dye\n```\n\n```tsx\nimport { dye } from 'react-dye'\n\n// Create a styled button with a danger variant\nconst Button = dye('px-4 py-2 rounded font-medium', {\n  default: 'bg-blue-500 hover:bg-blue-600',\n  danger: 'bg-red-500 hover:bg-red-600'\n}, 'button')\n\n// Apply the same styles to a link\nconst ButtonLink = Button.as('a')\n\n// Extend with additional classes and variants\nconst BigButton = Button.extend('text-3xl', {\n  success: 'bg-green-500 hover:bg-green-600',\n})\n\n// Use as normal component\nfunction App() {\n  return (\n    \u003cdiv\u003e\n      \u003cButton\u003ePrimary Action\u003c/Button\u003e {/* applies `default` variant by default */}\n      \u003cButton variant=\"danger\"\u003eDanger Action\u003c/Button\u003e\n      \u003cBigButton variant=\"danger\"\u003eBig Danger!\u003c/BigButton\u003e\n      \u003cButtonLink href=\"#\"\u003eLink\u003c/ButtonLink\u003e {/* has the same props as the base element */}\n    \u003c/div\u003e\n  )\n}\n```\n\n## Features\n\n- Zero dependencies.\n- Lightweight (about **0.5kb** gzipped).\n- Create styled components with CSS classes (ideal when using TailwindCSS or similar).\n- Use variants to create different styles for the same component.\n- Extend existing components with additional classes/variants.\n- Clone components with different element.\n- Returns fully typed components.\n\n## Documentation\n\nThis library exports two functions:\n- `dye`: creates a styled component with CSS classes and variants.\n- `create_dye`: creates a new `dye` function with custom config.\n\n### Using `dye` to style HTML elements\n\nIn its simplest form, `dye` takes some CSS classes and an HTML tag, and returns a component that applies the CSS classes to the element.\n\n```tsx\nimport { dye } from 'react-dye'\nconst Title = dye('mb-2 text-2xl', 'h1')\n\n\u003cTitle\u003econtent\u003c/Title\u003e\n```\nwill render\n```html\n\u003ch1 className=\"mb-2 text-2xl\"\u003econtent\u003c/h1\u003e\n```\n\n\u003chr\u003e\n\nThe `tag` is optional, and it defaults to `div`.\n\n```tsx\nconst Section = dye('p-3 mb-4')\n\u003cSection\u003econtent\u003c/Section\u003e\n```\nwill render\n```html\n\u003cdiv className=\"p-3 mb-4\"\u003econtent\u003c/div\u003e\n```\n\n\u003chr\u003e\n\nYou can pass additional CSS classes to the component using `className` and they will be added\n```tsx\nconst Section = dye('p-3 mb-4')\n\u003cSection className=\"font-bold\"\u003econtent\u003c/Section\u003e\n```\nwill render\n```html\n\u003cdiv className=\"p-3 mb-4 font-bold\"\u003econtent\u003c/div\u003e\n```\n\n**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.**\n\n### Defining variants\n\nSometimes 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.\n\n```tsx\nconst Button = dye('px-4 py-2 rounded', {\n  default: 'bg-blue-500 hover:bg-blue-600',\n  success: 'bg-green-500 hover:bg-green-600',\n  danger: 'bg-red-500 hover:bg-red-600',\n}, 'button')\n\n\u003cButton\u003eDefault Button\u003c/Button\u003e\n\u003cButton variant=\"success\"\u003eSuccess Button\u003c/Button\u003e\n\u003cButton variant=\"danger\"\u003eDanger Button\u003c/Button\u003e\n```\nwill render\n```html\n\u003cbutton className=\"px-4 py-2 rounded bg-blue-500 hover:bg-blue-600\"\u003eDefault Button\u003c/button\u003e\n\u003cbutton className=\"px-4 py-2 rounded bg-green-500 hover:bg-green-600\"\u003eSuccess Button\u003c/button\u003e\n\u003cbutton className=\"px-4 py-2 rounded bg-red-500 hover:bg-red-600\"\u003eDanger Button\u003c/button\u003e\n```\n\nWhen the `variant` property is passed to the component, the corresponding classes are added to the element.\n\nNote that the `default` variant is applied by default if defined.\n\n### Applying the same styles to a different HTML element\n\nWhat 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.\n\n```tsx\nimport {dye} from 'react-dye'\n\nconst Button = dye('px-4 py-2 rounded', {\n  default: 'bg-blue-500 hover:bg-blue-600',\n  success: 'bg-green-500 hover:bg-green-600',\n  danger: 'bg-red-500 hover:bg-red-600',\n}, 'button')\n\nconst ButtonLink = Button.as('a') // returns a new component that renders `a` instead of `button`\n\u003cButtonLink variant=\"success\" href=\"#\"\u003eLink\u003c/ButtonLink\u003e\n```\nwill render\n```html\n\u003ca className=\"px-4 py-2 rounded bg-green-500 hover:bg-green-600\" href=\"#\"\u003eLink\u003c/a\u003e\n```\n\n### Extending classes and variants of a component\n\nSame 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.\n\n```tsx\nimport {dye} from 'react-dye'\n\nconst Button = dye('px-4 py-2 rounded', {\n  default: 'bg-blue-500 hover:bg-blue-600',\n  success: 'bg-green-500 hover:bg-green-600',\n  danger: 'bg-red-500 hover:bg-red-600',\n}, 'button')\n\nconst BigButton = Button.extend('text-3xl font-semibold') // adds new classes\nconst SpecialButton = Button.extend('', {\n  bonus: 'bg-orange-500 hover:bg-orange-600', // adds new variant\n  success: 'border-2 border-green-300', // adds classes to existing variant\n})\n\n\u003cBigButton variant=\"danger\"\u003eStop\u003c/BigButton\u003e\n\u003cSpecialButton variant=\"bonus\"\u003eBonus\u003c/SpecialButton\u003e\n\u003cSpecialButton variant=\"success\"\u003eCongratulations\u003c/SpecialButton\u003e\n```\nwill render\n```html\n\u003cbutton className=\"px-4 py-2 rounded text-3xl font-semibold bg-red-500 hover:bg-red-600\"\u003eStop\u003c/button\u003e\n\u003cbutton className=\"px-4 py-2 rounded bg-orange-500 hover:bg-orange-600\"\u003eBonus\u003c/button\u003e\n\u003cbutton className=\"px-4 py-2 rounded bg-green-500 hover:bg-green-600 border-2 border-green-300\"\u003eCongratulations\u003c/button\u003e\n```\n\n**Note that:**\n- The additional classes are added to the existing classes.\n- When extending an existing variant, the additional classes are added to the old ones.\n\nif 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.\n\n### Creating a new `dye` function with custom config\n\nif 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.\n\nThe config has the following type:\n```ts\ntype Config = {\n  mergeClasses: (classes: ClassValue[]) =\u003e string\n}\n\ntype ClassValue = string | undefined | null | false\n```\n- `mergeClasses` the function to use to filter out falsy classnames and merge the rest. The default implementation just joins the classes with a space.\n\nThat's all it's on the config now, if you see other behaviors/flags to add, please let me know :)\n\nCheck a pratical example of using `create_dye` in the [Merging TailwindCSS classes without conflict](#merging-tailwindcss-classes-without-conflict) guide below.\n\n## Merging TailwindCSS classes without conflict\n\nWhen using TailwindCSS, you probably want to avoid conflicts, simply concatenating classenames will not work. So follow the next steps:\n\n1. Add [tailwind-merge](https://github.com/tailwindlabs/tailwind-merge) to your project\n```\nnpm install tailwind-merge\n```\n\n2. Create a custom `dye` function that uses `twMerge` from `tailwind-merge`:\n```ts\nimport { create_dye } from 'react-dye'\nimport { twMerge } from 'tailwind-merge'\n\nexport const dye = create_dye({ mergeClasses: twMerge })\n```\n\n3. Use the `dye` function exported above instead of the default one.\n\nThat's all.\n\nNow you may have the following question: _Why not just include `tailwind-merge` as a dependency and use `twMerge` by default?_\n\nI decided not to include it because:\n- I would like this library to be generic, works with any collection of CSS classes. I don't want to tie it to TailwindCSS.\n- `tailwind-merge` is great, but it would multiply the bundle size by **16**! (8kb vs 0.5kb).\n\n## Contributing\n\nYou can contribute to this library in many ways, including:\n\n- **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.\n- **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.\n\nThose are just examples, any issue or pull request is welcome :)\n\n## Changelog\n\nCheck out the [changelog](https://github.com/webneat/react-dye/blob/main/CHANGELOG.md) for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebneat%2Freact-dye","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwebneat%2Freact-dye","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebneat%2Freact-dye/lists"}