{"id":14962145,"url":"https://github.com/brandonmcconnell/tailwindcss-signals","last_synced_at":"2025-05-16T03:02:54.441Z","repository":{"id":231106753,"uuid":"780933510","full_name":"brandonmcconnell/tailwindcss-signals","owner":"brandonmcconnell","description":"Signals for Tailwind CSS simplifies styling based on ancestor state via style queries. Its declarative API for signaling states eliminates complex selectors, resulting in cleaner, more maintainable code.","archived":false,"fork":false,"pushed_at":"2024-05-07T23:26:24.000Z","size":579,"stargazers_count":784,"open_issues_count":3,"forks_count":11,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-05-12T04:16:10.842Z","etag":null,"topics":["tailwind","tailwind-css","tailwindcss","tailwindcss-plugin"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/brandonmcconnell.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":"2024-04-02T12:44:45.000Z","updated_at":"2025-05-09T13:33:41.000Z","dependencies_parsed_at":null,"dependency_job_id":"0cbd5052-91ba-4f47-83e9-6924f0cbc647","html_url":"https://github.com/brandonmcconnell/tailwindcss-signals","commit_stats":null,"previous_names":["brandonmcconnell/tailwindcss-signals"],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brandonmcconnell%2Ftailwindcss-signals","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brandonmcconnell%2Ftailwindcss-signals/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brandonmcconnell%2Ftailwindcss-signals/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brandonmcconnell%2Ftailwindcss-signals/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/brandonmcconnell","download_url":"https://codeload.github.com/brandonmcconnell/tailwindcss-signals/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254459081,"owners_count":22074604,"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":["tailwind","tailwind-css","tailwindcss","tailwindcss-plugin"],"created_at":"2024-09-24T13:29:32.699Z","updated_at":"2025-05-16T03:02:49.431Z","avatar_url":"https://github.com/brandonmcconnell.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eSignals for Tailwind CSS\u003c/h1\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n[![minified size](https://img.shields.io/bundlephobia/min/tailwindcss-signals)](https://bundlephobia.com/package/tailwindcss-signals)\n[![license](https://img.shields.io/github/license/brandonmcconnell/tailwindcss-signals?label=license)](https://github.com/brandonmcconnell/tailwindcss-signals/blob/main/LICENSE)\n[![version](https://img.shields.io/npm/v/tailwindcss-signals)](https://www.npmjs.com/package/tailwindcss-signals)\n[![twitter](https://img.shields.io/twitter/follow/branmcconnell)](https://twitter.com/branmcconnell)\n\n\u003c/div\u003e\n\n\u003ctable\u003e\u003ctr\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\n\n### ⚠️ This plugin is experimental and relies on [style queries](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Container_size_and_style_queries#container_style_queries_2) (via container queries), which are not yet widely supported in browsers.\n\nThe good news is that Safari and Firefox, the browsers lacking support, have already begun implementing style queries in their development versions, so it's only a matter of time before they're widely available.\n\nSee the browser compatibility table on [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Container_size_and_style_queries#browser_compatibility) or [caniuse](https://caniuse.com/css-container-queries-style) for more information.\n\n\u003cbr\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\nSignals for Tailwind CSS is a plugin that utilizes [style queries](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Container_size_and_style_queries#container_style_queries_2) (via container queries) to reactively enable a custom state, which can then be consumed by any of its descendants in the DOM.\n\n`signal` is similar to the existing `group` variant/utility in that both provide methods for styling elements based on their ancestors' state. Unlike `group` states, however, signal states can be explicitly signaled, allowing their state to be both set and consumed with a single, simple, unchained variant.\n\nThis reduces development effort and the need to compose a chain of variants, improving the developer experience with a more declarative API.\n\nDepending on your use case, a traditional `group` may make more sense, but often, particularly when managing a parent or ancestor state with anything more complex than a simple `peer-X` or `group-X`, a `signal` may be a simpler option.\n\n## Installation\n\nYou can install the plugin via npm:\n\n```bash\nnpm install tailwindcss-signals\n```\n\nThen, include it in your `tailwind.config.js`:\n\n```js\nmodule.exports = {\n  plugins: [\n    require('tailwindcss-signals'),\n  ]\n}\n```\n\n## Usage\n\nThe plugin introduces the `signal` variant, which can be used to apply styles based on an ancestor's signaled state.\n\nHere's an example comparing the traditional approach with the new signals approach:\n\n\u003ctable\u003e\u003ctr\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\n\n#### Example: Without Signals\n```html\n\u003cinput type=\"checkbox\" class=\"peer\" /\u003e 👈🏼 check/uncheck here\n\u003cdiv class=\"hover:[\u0026\u003ediv]:bg-green-800 peer-checked:[\u0026\u003ediv]:bg-green-800\"\u003e\n  \u003cdiv class=\"bg-red-800 p-1 text-white\"\u003eor hover here\u003c/div\u003e\n\u003c/div\u003e\n```\nOpen this example in Tailwind Play: https://play.tailwindcss.com/E3ig9SPTsc\n\n\u003cbr\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\n\n#### Example: With Signals\n```html\n\u003cinput type=\"checkbox\" class=\"peer\" /\u003e 👈🏼 check/uncheck here\n\u003cdiv class=\"peer-checked:signal hover:signal\"\u003e\n  \u003cdiv class=\"signal:bg-green-800 bg-red-800 p-1 text-white\"\u003eor hover here\u003c/div\u003e\n\u003c/div\u003e\n```\nOpen this example in Tailwind Play: https://play.tailwindcss.com/weFkMf4U5K\n\n\u003cbr\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\nNotice how, with signals, we don't have to use any arbitrary selector variants like `[\u0026\u003ediv]` and can instead apply those styles directly to the targeted descendants. This allows us to consolidate some redundancy in the parent so that whatever condition activates the signal only needs to be specified once rather than once per style/utility.\n\nThe benefits of Signals for Tailwind CSS become more apparent as the complexity of your styles and conditions increase.\n\n### Activating a `signal` based on a descendant condition\n\nThe general purpose of this plugin is to provide a declarative approach to applying styles based on an _**ancestor's**_ state.\n\nHowever, thanks to the power of the [`:has()`](https://developer.mozilla.org/en-US/docs/Web/CSS/:has) CSS pseudo-class, we can even activate a signal based on a _**descendant's**_ state.\n\n\u003ctable\u003e\u003ctr\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\n\n#### Example: Descendant condition\n```html\n\u003cdiv class=\"has-[:is(input:checked,div:hover)]:signal\"\u003e\n  \u003cinput type=\"checkbox\" /\u003e 👈🏼 check/uncheck here\n  \u003cdiv class=\"bg-red-800 p-1 text-white signal:bg-green-800\"\u003eor hover here\u003c/div\u003e\n\u003c/div\u003e\n```\nOpen this example in Tailwind Play: https://play.tailwindcss.com/YnlzSITNqF\n\n\u003cbr\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\nThis is most useful for situations where you want to apply styles to an entire block based on the current state of one of its descendants.\n\nHere are a few examples of cases where such a feature might be useful:\n* Activating a signal based on the presence or visibility of a specific child element\n* Activating a signal on a form based on the validity of one or more of its descendant form fields\n* Activating a signal when a specific descendant element is focused or hovered\n* Activating a signal based on the presence of a specific class on a descendant element\n* and many more!\n\n⚠️ Some cautions:\n* Watch out for circularity issues. If you set up a signal that activates based on a descendant's state, and that descendant's state is also based on the signal, you may run into issues.\n* In some cases, if you want to check if **any** descendant is focused, for example, you may not need `:has()` and could use a simpler pseudo-class variant such as…\n  * `focus-within:signal` instead of `has-[:focus]:signal`\n  * `valid:signal` instead of `has-[:valid]:signal` (for a `form`, which checks if all form contents are valid)\n* This is a bit less declarative when you use `:has()`, but for use cases where you would need it, it would likely still be simpler than the alternative.\n\n### Differentiating signals\n\nWhen using multiple signals, you may run into situations where you want one signal nested in another, which could cause issues. In that case, you can distinguish signals apart by naming them using the modifier syntax built into Tailwind CSS, the same naming convention used for `group` and `peer` variants.\n\n\n\u003ctable\u003e\u003ctr\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\n\n#### Example: Naming a signal\n```html\n\u003cinput type=\"checkbox\" class=\"peer/checkable origin-bottom-left\" /\u003e 👈🏼 check/uncheck here\n\u003cdiv class=\"peer/hoverable bg-slate-700 text-white\"\u003e✨ hover/unhover here ✨\u003c/div\u003e\n\u003cdiv class=\"active:signal/custom peer-checked/checkable:signal peer-hover/hoverable:signal\"\u003e\n  \u003cdiv class=\"\n    text-white\n    bg-red-800 after:content-['_👀']\n    signal/custom:!bg-purple-800 signal:bg-green-800\n    signal/custom:after:!content-['_🦄'] signal:after:content-['_😱']\n  \"\u003epress me\u003c/div\u003e\n\u003c/div\u003e\n```\nOpen this example in Tailwind Play: https://play.tailwindcss.com/MkWvEuaWtO\n\n\u003cbr\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\nBy giving a signal a name, you can ensure it is unique and doesn't conflict with other signals. You can name a signal by adding a slash and the name after the `signal` variant, like `signal/{name}`.\n\nConsuming a named signal is the same as consuming a regular signal, but with the name appended to the variant: `signal/{name}`.\n\n\u003ci\u003e\u003csmall\u003eFor more information on this modifier syntax, see [Differentiating peers](https://tailwindcss.com/docs/hover-focus-and-other-states#differentiating-peers) from the official Tailwind CS documentation.\u003c/small\u003e\u003c/i\u003e\n\n## Why use Signals for Tailwind CSS?\n\nSignals for Tailwind CSS provides a more declarative and straightforward approach to applying styles based on an ancestor's state. Leveraging style queries (via container queries) eliminates the need for complex selector chaining and arbitrary targeting, resulting in a cleaner and more maintainable codebase.\n\nThis plugin is particularly useful for:\n\n- Simplifying the application of styles based on ancestor states\n- Improving developer experience with a more declarative API\n- Reducing the need for complex selector chaining and arbitrary targeting\n\n## Why NOT use Signals for Tailwind CSS?\n\n**⚠️ Browser support for [style queries](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Container_size_and_style_queries#container_style_queries_2) is still limited, so Signals for Tailwind CSS may not be suitable for projects that require broad compatibility.**\n\nThe good news is that Safari and Firefox, the browsers lacking support, have already begun implementing style queries in their development versions, so it's only a matter of time before they're widely available.\n\nSee the browser compatibility table on [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Container_size_and_style_queries#browser_compatibility) or [caniuse](https://caniuse.com/css-container-queries-style) for more information.\n\n\n---\n\nI hope you find `tailwindcss-signals` a valuable addition to your projects. If you have any issues or suggestions, don't hesitate to open an issue or pull request.\n\nIf you liked this, you might also like my other Tailwind CSS plugins:\n* [tailwindcss-multi](https://github.com/brandonmcconnell/tailwindcss-multi): Group utilities together by variant\n* [tailwindcss-mixins](https://github.com/brandonmcconnell/tailwindcss-mixins): Construct reusable \u0026 aliased sets of utilities inline\n* [tailwindcss-members](https://github.com/brandonmcconnell/tailwindcss-members): Apply styles based on child or descendant state, the inverse of groups\n* [tailwindcss-selector-patterns](https://github.com/brandonmcconnell/tailwindcss-selector-patterns): Dynamic CSS selector patterns\n* [tailwindcss-js](https://github.com/brandonmcconnell/tailwindcss-js): Effortless build-time JS script injection\n* [tailwindcss-directional-shadows](https://github.com/brandonmcconnell/tailwindcss-directional-shadows): Supercharge your shadow utilities with added directional support (includes directional `shadow-border` utilities too ✨)\n* [tailwindcss-default-shades](https://github.com/brandonmcconnell/tailwindcss-default-shades): Default shades for simpler color utility classes\n* [tailwind-lerp-colors](https://github.com/brandonmcconnell/tailwind-lerp-colors): Expand your color horizons and take the fuss out of generating new—or expanding existing—color palettes","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrandonmcconnell%2Ftailwindcss-signals","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrandonmcconnell%2Ftailwindcss-signals","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrandonmcconnell%2Ftailwindcss-signals/lists"}