{"id":47981194,"url":"https://github.com/taranek/tailwind-nested","last_synced_at":"2026-04-04T11:05:27.919Z","repository":{"id":314956146,"uuid":"1057486021","full_name":"taranek/tailwind-nested","owner":"taranek","description":"Organize your Tailwind CSS classes with nested selectors for better maintainability and cleaner code.","archived":false,"fork":false,"pushed_at":"2025-09-23T08:45:03.000Z","size":318,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-10-26T03:05:53.245Z","etag":null,"topics":["classnames","nesting","styling","tailwind","tailwindcss","tailwindcss-v4"],"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/taranek.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-15T19:44:11.000Z","updated_at":"2025-10-06T16:11:55.000Z","dependencies_parsed_at":"2025-09-15T22:24:39.821Z","dependency_job_id":"198f1f8c-2b9f-4c2f-a855-465195f6db1a","html_url":"https://github.com/taranek/tailwind-nested","commit_stats":null,"previous_names":["taranek/tailwind-nested"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/taranek/tailwind-nested","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taranek%2Ftailwind-nested","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taranek%2Ftailwind-nested/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taranek%2Ftailwind-nested/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taranek%2Ftailwind-nested/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/taranek","download_url":"https://codeload.github.com/taranek/tailwind-nested/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taranek%2Ftailwind-nested/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31397056,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T10:20:44.708Z","status":"ssl_error","status_checked_at":"2026-04-04T10:20:06.846Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["classnames","nesting","styling","tailwind","tailwindcss","tailwindcss-v4"],"created_at":"2026-04-04T11:05:27.828Z","updated_at":"2026-04-04T11:05:27.898Z","avatar_url":"https://github.com/taranek.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tailwind-nested\n\nOrganize your Tailwind CSS classes with nested selectors for better maintainability and cleaner code.\n\n## The Problem\n\nComplex Tailwind components often end up with messy, hard-to-maintain class strings:\n\n```jsx\n// ❌ Traditional approach - hard to read and maintain\n\u003cbutton className={`\n  px-6 py-3 bg-blue-600 text-white font-semibold rounded-lg transition-all duration-200\n  hover:bg-blue-700 hover:shadow-lg hover:scale-105\n  focus:outline-none focus:ring-4 focus:ring-blue-300 focus:ring-opacity-50\n  active:scale-95 active:bg-blue-800\n  disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-blue-600 disabled:hover:scale-100 disabled:hover:shadow-none\n  dark:bg-blue-500 dark:hover:bg-blue-600 dark:focus:ring-blue-400\n  md:px-8 md:py-4 md:text-lg\n`}\u003e\n  Submit Form\n\u003c/button\u003e\n```\n\n## The Solution\n\nWith tailwind-nested, organize your styles with clean, nested objects:\n\n```jsx\n// ✅ With tailwind-nested - organized and maintainable\nimport { twn } from 'tailwind-nested';\n\n\u003cbutton className={twn('px-6 py-3 bg-blue-600 text-white font-semibold rounded-lg transition-all duration-200', {\n  // Interactive states\n  hover: 'bg-blue-700 shadow-lg scale-105',\n  focus: 'outline-none ring-4 ring-blue-300 ring-opacity-50',\n  active: 'scale-95 bg-blue-800',\n  \n  // Disabled state\n  disabled: {\n    '\u0026': 'opacity-50 cursor-not-allowed',\n    hover: 'bg-blue-600 scale-100 shadow-none',\n  },\n  \n  // Dark mode\n  dark: {\n    '\u0026': 'bg-blue-500',\n    hover: 'bg-blue-600',\n    focus: 'ring-blue-400',\n  },\n  \n  // Responsive\n  md: 'px-8 py-4 text-lg',\n})}\u003e\n  Submit Form\n\u003c/button\u003e\n```\n\n## Installation\n\n```bash\nnpm install tailwind-nested\n\nyarn add tailwind-nested\n\npnpm add tailwind-nested\n\nbun add tailwind-nested\n```\n\n## Vite Configuration\n\nAdd the Vite plugin to extract classes for Tailwind's JIT compiler. **Important:** The plugin must be added **before** the `tailwindcss()` plugin.\n\n```js\n// vite.config.js\nimport { defineConfig } from 'vite';\nimport { twnPlugin } from 'tailwind-nested/vite';\nimport tailwindcss from '@tailwindcss/vite';\n\nexport default defineConfig({\n  plugins: [\n    twnPlugin(),      // ← Add this BEFORE tailwindcss\n    tailwindcss(),    // ← tailwindcss comes after\n  ],\n});\n```\n\n## Usage\n\nThe Tailwind Nested plugin provides a `twn()` function, which you use to declare the TailwindCSS utilities you want to apply in a `class` or `className` attribute. The examples below are shown using React JSX syntax, but the plugin works with any JavaScript framework.\n\n### Basic usage\n\nHighlight the repeated variants as object keys, then list only the necessary utilities as values. Remember, in both development and production, the final class name list is generated by the Tailwind Nested plugin through the `twn()` function.\n\n```jsx\nimport { twn } from 'tailwind-nested';\n\n\u003cbutton className={twn('bg-blue-500 text-white px-4 py-2 rounded-md font-medium', {\n  dark: 'bg-blue-600',\n  hover: 'bg-blue-600 shadow-lg transform scale-105',\n  focus: 'outline-none ring-2 ring-blue-500 ring-offset-2',\n})}\u003e\n  Click me\n\u003c/button\u003e\n```\n\n### Stacking in the key\n\nYou can also reference multiple variants together by joining them with a colon (`:`) in the key.\n\n```jsx\nimport { twn } from 'tailwind-nested';\n\n\u003cbutton className={twn('bg-blue-500 text-white px-4 py-2 rounded-md font-medium', {\n  dark: 'bg-blue-600',\n  hover: 'bg-blue-600 shadow-lg transform scale-105',\n  'dark:hover': 'bg-blue-700',\n  focus: 'outline-none ring-2 ring-blue-500 ring-offset-2',\n  'dark:focus': 'bg-blue-600',\n})}\u003e\n  Click me\n\u003c/button\u003e\n```\n\n### Stacking in nested objects\n\nYou can also reference multiple variants together using nested objects, where the inner object's key inherits the parent key.\n\n```jsx\nimport { twn } from 'tailwind-nested';\n\n\u003cbutton className={twn('bg-blue-500 text-white px-4 py-2 rounded-md font-medium', {\n  hover: 'bg-blue-600 shadow-lg transform scale-105',\n  focus: 'outline-none ring-2 ring-blue-500 ring-offset-2',\n  dark: {\n    '\u0026': 'bg-blue-600',\n    hover: 'bg-blue-700',\n    focus: 'bg-blue-600',\n  }\n})}\u003e\n  Click me\n\u003c/button\u003e\n```\n\n### ARIA Attribute Selectors\n\nPerfect for accessibility-based styling with nested selectors:\n\n```jsx\nfunction AriaDemo() {\n  const [expanded, setExpanded] = useState(false);\n  \n  return (\n    \u003cbutton\n      aria-expanded={expanded}\n      onClick={() =\u003e setExpanded(!expanded)}\n      className={twn('flex items-center justify-between w-full p-3 bg-white border rounded-md', {\n        'aria-[expanded=true]': {\n          // root styles for the aria-[expanded=true] state\n          '\u0026': 'bg-blue-50 border-blue-300',\n          '[\u0026_svg]': 'rotate-180'\n        },\n        'aria-[expanded=false]': 'bg-gray-50 border-gray-300',\n        hover: 'shadow-sm',\n        focus: 'outline-none ring-2 ring-blue-500',\n      })}\n    \u003e\n      \u003cspan\u003eCollapsible Section\u003c/span\u003e\n      \u003csvg className=\"w-5 h-5 transition-transform\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\"\u003e\n        \u003cpath strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" /\u003e\n      \u003c/svg\u003e\n    \u003c/button\u003e\n  );\n}\n```\n\n### Data Attribute Selectors\n\nDynamic styling based on data attributes:\n\n```jsx\nfunction FormDemo() {\n  const [email, setEmail] = useState('');\n  const [isValid, setIsValid] = useState(null);\n  \n  return (\n    \u003cinput\n      type=\"email\"\n      value={email}\n      onChange={handleChange}\n      data-valid={isValid}\n      className={twn('w-full px-3 py-2 border rounded-md', {\n        'data-[valid=true]': 'border-green-300 focus:ring-green-500',\n        'data-[valid=false]': 'border-red-300 focus:ring-red-500', \n        'data-[valid=null]': 'border-gray-300 focus:ring-blue-500',\n        focus: 'outline-none ring-2 ring-opacity-50',\n        hover: 'border-gray-400',\n      })}\n      placeholder=\"Enter your email\"\n    /\u003e\n  );\n}\n```\n\n## Features\n\n- 🎯 **TypeScript support** - Basic intellisense for Tailwind variants  \n- ✨ **Nested selectors** - Organize complex state combinations\n- ⚡  **Vite plugin** - Extract classnames at build time for no performance overhead\n- 🔧 **Framework agnostic** - Works with React, Vue, Svelte, and more\n- 📦 **Zero runtime** - Compiles to standard Tailwind classes\n\n## Compatibility\n\n**✅ Supported:**\n- Vite projects (React, Vue, Svelte, etc.)\n- Any bundler when using only the `twn()` function\n\n**❌ Not yet supported:**\n- Astro (class extraction plugin doesn't work with Astro's build process)\n- Webpack, Rollup, or other bundlers (plugin support coming soon)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftaranek%2Ftailwind-nested","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftaranek%2Ftailwind-nested","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftaranek%2Ftailwind-nested/lists"}