{"id":15289051,"url":"https://github.com/lukewatts/react-windstorm","last_synced_at":"2026-01-05T22:05:35.563Z","repository":{"id":153181680,"uuid":"628372248","full_name":"lukewatts/react-windstorm","owner":"lukewatts","description":"React Windstorm will create a Tailwind CSS theme provider which allows for quickly creating a Tailwind CSS theme for your React pages or components.","archived":false,"fork":false,"pushed_at":"2024-01-06T09:45:01.000Z","size":92,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-23T19:51:37.962Z","etag":null,"topics":["hooks","provider","react","tailwind","tailwind-css","tailwindcss","theme","themeprovider"],"latest_commit_sha":null,"homepage":"","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/lukewatts.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2023-04-15T18:35:18.000Z","updated_at":"2024-03-30T22:15:50.000Z","dependencies_parsed_at":null,"dependency_job_id":"bf2a5e05-aab0-4fbf-8638-8b750fb2843c","html_url":"https://github.com/lukewatts/react-windstorm","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukewatts%2Freact-windstorm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukewatts%2Freact-windstorm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukewatts%2Freact-windstorm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukewatts%2Freact-windstorm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lukewatts","download_url":"https://codeload.github.com/lukewatts/react-windstorm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245217791,"owners_count":20579297,"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":["hooks","provider","react","tailwind","tailwind-css","tailwindcss","theme","themeprovider"],"created_at":"2024-09-30T15:58:39.433Z","updated_at":"2026-01-05T22:05:35.533Z","avatar_url":"https://github.com/lukewatts.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# React Windstorm\n\n## What\n\nReact Windstorm will create a Tailwind CSS theme provider which allows for quickly creating a Tailwind CSS theme for your React pages or components which can be completely decoupled from your component/application markup.\n\n## Why\n\nTailwindCSS is great! It makes styling an application or component super fast and less error prone and means you no longer have to maintain one or multiple stylesheets.\n\nHowever, it has some downside too. Mainly, putting Tailwind classes directly into your HTML isn't very SOLID and actually creates a whole new set of maintainance issues. React Windstorm solves some of these issues by allowing themes to be completely seperate from their markup and allowing className strings in a theme to be re-used in other className strings with ease. Any property in your theme object can be re-used as part of any other properties value, meaning no duplication.\n\n### Separation of concerns/Open-closed Principal\n\nHaving all your Tailwind classes in your components HTML means your styles and your markup are very tightly coupled to one another. If you want to tweak your styles, you have to edit the component itself. By using a theme provider instead, your styles can be managed completely seperately from your component. And because they are simply an object or a JSON file, you don't even need the developer who is editing them to be aware of the component or even know any React. Tailwind knowledge will be all they need. Likewise, developers working in the component file will no longer need to see all the classNames everywhere, which is less visual clutter for them to focus on the functionality.\n\n### DRY (Don't Repeat Yourself)\n\nIn React particularly, there isn't really the opportunity to use the @apply method of creating reusable classes unless you go back to writing stylesheets. It's also not really recommended to use @apply all that much since you would just end up back writing hard to maintain stylesheets. However, putting all of your classes in the HTML will inevitably lead to a lot more duplication in your className strings. React Windstorm solves this by allowing better composition and reuse of logical Tailwind class groups.\n\n### Semantics\n\nBy grouping your Tailwind classes into a single property, we can create \"classnames\" that actually describe what that element is. Also, with the reusable properties variables we can better describe what is happening in our className strings.\n\nThe raw Tailwind way...\n\n```jsx\nexport default () =\u003e {\n    const {theme} = useTheme();\n\n    return (\n        \u003cmain className=\"grid min-h-full place-items-center bg-white px-6 py-24 sm:py-32 lg:px-8\"\u003e\n            \u003cdiv className=\"text-center\"\u003e\n                \u003cp className=\"text-base font-semibold text-indigo-600\"\u003e404\u003c/p\u003e\n                \u003ch1 className=\"mt-4 text-3xl font-bold tracking-tight text-gray-900 sm:text-5xl\"\u003ePage not found\u003c/h1\u003e\n                \u003cp className=\"mt-6 text-base leading-7 text-gray-600\"\u003eSorry, we couldn’t find the page you’re looking for.\u003c/p\u003e\n                \u003cdiv className=\"mt-10 flex items-center justify-center gap-x-6\"\u003e\n                    \u003ca href=\"#\" className=\"rounded-md bg-indigo-600 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600\"\u003eGo back home\u003c/a\u003e\n                    \u003ca href=\"#\" className=\"text-sm font-semibold text-gray-900\"\u003eContact support \u003cspan aria-hidden=\"true\"\u003e\u0026rarr;\u003c/span\u003e\u003c/a\u003e\n                \u003c/div\u003e\n            \u003c/div\u003e\n        \u003c/main\u003e\n    );\n};\n```\n\nIt probably didn't take you long to figure out this is a 404 page component. However, it probably took you longer to spot what exactly each element is for, or how many columns there are or are those links styled like links or buttons, and so on. There's just a lot of visual noise caused by Tailwind, even in a simple component like this.\n\nNow let's see the same markup but with all the Tailwind stuff moved out of the component and into a `createTailwindTheme` provider.\n\n```jsx\nconst useTheme = createTheme({\n    fullHeightColumnCentered: \"grid min-h-full place-items-center px-6 py-24 sm:py-32 lg:px-8 bg-white\",\n    textCentered: \"text-center\",\n    statusCode: \"text-base font-semibold text-indigo-600\",\n    statusMessage: \"mt-4 text-3xl font-bold tracking-tight text-gray-900 sm:text-5xl\",\n    helpText: \"mt-6 text-base leading-7 text-gray-600\",\n    callToActionContainer: \"mt-10 flex items-center justify-center gap-x-6\",\n    homeLinkButton: \"px-3.5 py-2.5 text-sm font-semibold text-white rounded-md shadow-sm bg-indigo-600 hover:bg-indigo-500 focus-visible:outline  focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600\",\n    supportLink: \"text-sm font-semibold text-gray-900\"\n});\n```\n\nYou can probably already tell exactly what is going on just from this. But it becomes very obvious when we use the theme in out component\n\n```jsx\nexport default () =\u003e {\n    const {theme} = useTheme();\n\n    return (\n        \u003cmain className={theme.fullHeightColumnCentered}\u003e\n            \u003cdiv className={theme.textCentered}\u003e\n                \u003cp className={theme.statusCode}\u003e404\u003c/p\u003e\n                \u003ch1 className={theme.statusMessage}\u003ePage not found\u003c/h1\u003e\n                \u003cp className={theme.helpText}\u003eSorry, we couldn’t find the page you’re looking for.\u003c/p\u003e\n                \u003cdiv className={theme.callToActionContainer}\u003e\n                    \u003ca href=\"#\" className={theme.homeLinkButton}\u003eGo back home\u003c/a\u003e\n                    \u003ca href=\"#\" className={theme.supportLink}\u003eContact support \u003cspan aria-hidden=\"true\"\u003e\u0026rarr;\u003c/span\u003e\u003c/a\u003e\n                \u003c/div\u003e\n            \u003c/div\u003e\n        \u003c/main\u003e\n    );\n});\n```\n\n## How\n\n### Step 1. \n\nInstall and configure React and Tailwind as normal using the instructions on the [TailwindCSS docs](https://tailwindcss.com/docs/guides/vite#react)\n\n### Step 2.\n\nInstall React Windstorm from npm:\n\n`yarn add -D react-windstorm`\n\nIn a component, create a theme and apply it like so:\n\n```jsx\nimport { createTheme } from \"react-windstorm\";\n\nconst useTheme = createTheme({\n    // ----------------------------------------\n    // Helper Classes\n    // ----------------------------------------\n    gridFullHeightCentered: \"grid min-h-full place-items-center\",\n    padding_x6_y24: \"px-6 py-24 sm:py-32 lg:px-8\",\n    semibold: \"font-semibold\", // We can create reusable items. Call them in other properties by prefixing the key with @ (e.g. @semibold). This can also be a way to easily alias reusable chunks, or simply alias something so it makes more sense for you project\n    textSmallSemiBold: \"text-sm font-semibold\",\n    text3xlBold: \"text-3xl font-bold tracking-tight text-gray-900 sm:text-5xl\",\n    standardParagraphText: \"text-base leading-7 text-gray-600\",\n    flexRowWithCenteredItems: \"flex items-center justify-center\",\n    linkButtonPadding: \"px-3.5 py-2.5\",\n    indigoButtonRounded: \"text-white rounded-md shadow-sm bg-indigo-600 hover:bg-indigo-500 focus-visible:outline  focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600\",\n\n    // ----------------------------------------\n    // Theme Classes\n    // ----------------------------------------\n    fullHeightColumnCentered: \"@gridFullHeightCentered @padding_x6_y24 bg-white\",\n    textCentered: \"text-center\",\n    statusCode: \"text-base @semibold text-indigo-600\",\n    statusMessage: \"mt-4 @text3xlBold\",\n    helpText: \"mt-6 @standardParagraphText\",\n    callToActionContainer: \"mt-10 @flexRowWithCenteredItems gap-x-6\",\n    homeLinkButton: \"@linkButtonPadding @textSmallSemiBold @indigoButtonRounded\",\n    supportLink: \"@textSmallSemiBold text-gray-900\"\n});\n\nconst ErrorMessagePage = () =\u003e {\n    const {theme} = useTheme();\n\n    return (\n        \u003cmain className={theme.fullHeightColumnCentered}\u003e\n            \u003cdiv className={theme.textCentered}\u003e\n                \u003cp className={theme.statusCode}\u003e404\u003c/p\u003e\n                \u003ch1 className={theme.statusMessage}\u003ePage not found\u003c/h1\u003e\n                \u003cp className={theme.helpText}\u003eSorry, we couldn’t find the page you’re looking for.\u003c/p\u003e\n                \u003cdiv className={theme.callToActionContainer}\u003e\n                    \u003ca href=\"#\" className={theme.homeLinkButton}\u003eGo back home\u003c/a\u003e\n                    \u003ca href=\"#\" className={theme.supportLink}\u003eContact support \u003cspan aria-hidden=\"true\"\u003e\u0026rarr;\u003c/span\u003e\u003c/a\u003e\n                \u003c/div\u003e\n            \u003c/div\u003e\n        \u003c/main\u003e\n    );\n});\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flukewatts%2Freact-windstorm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flukewatts%2Freact-windstorm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flukewatts%2Freact-windstorm/lists"}