Skip to main content

daisyui

How a component's look is declared in an app that uses the daisyui gem with Phlex — modifiers, the `variants` block (defaults, compounds, hover/open/focus states, slots), Tailwind sources and introspection. Use when writing or changing a component's look, adding a modifier, a hover/open/focus state, or the classes of one of its parts.

Datos de origen

Repositorio
zoolutions/claude-plugins
Última actividad en el origen
26 de octubre de 2026 a las 18:45
Idioma detectado de SKILL.md
inglés
Estrellas
2
Forks
0

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
daisyui
description
How a component's look is declared in an app that uses the daisyui gem with Phlex — modifiers, the `variants` block (defaults, compounds, hover/open/focus states, slots), Tailwind sources and introspection. Use when writing or changing a component's look, adding a modifier, a hover/open/focus state, or the classes of one of its parts.
argument-hint
component, modifier, state or look to change
allowed-tools
Bash(*), Read, Write, Edit, Glob, Grep, Skill
model
sonnet
# DaisyUI looks: $ARGUMENTS **Read the repository first.** `AGENTS.md` → `## Workflow`: **UI kit** (the wrappers to call and the base class to subclass), **Views** (where components live), and any line on styling or generated Tailwind sources (the generated file's path, the stylesheet that imports it, the lint exclusion). Those facts override the defaults below. Everything here needs a gem version with `variants` (2.2.0, unreleased: the gem's `main` until it ships; check `DaisyUI::Base.respond_to?(:variants)`). ## Decision ladder Take the first rung that expresses the design. 1. **An existing modifier.** `Button(:ghost, :sm)`. Read the component's schema first (below). 2. **A `variants` declaration on the app's wrapper.** A new member, default, compound or state: the look lives in one class, as data, and every call site gets it. 3. **A Tailwind utility at the call site.** `Button(:primary, class: "w-full")` for a one-off layout need, never a look the component should own. 4. **CSS, only to extend the framework** (a token, `@utility`, `@custom-variant`), and only as the repository's own styling rule allows; it usually needs a human's approval. Never per-feature CSS, never `!important`. ## The `variants` block ```ruby class Tile < DaisyUI::Button # or the app's wrapper base variants do base "font-medium" # every instance, after the inherited base variant :tone, calm: "btn-ghost", loud: "btn-primary" # alternatives (one ClassMerge group) flag :wide, "btn-wide" # on/off; `flag :name` alone = no class default :tone, :calm # when the caller names no :tone compound tone: :loud, wide: true, class: "uppercase" state :hover, "hover" # name a Tailwind variant once on :hover, tone: :calm, class: "[--btn-bg:transparent]" slot :menu, "mt-2" # a part; see slot_classes below end end Tile() # btn font-medium btn-ghost hover:[--btn-bg:transparent] Tile(:loud, :wide) # btn font-medium btn-primary btn-wide uppercase ``` | Declaration | Meaning | |---|---| | `base "…"` | Classes every instance gets. | | `variant :group, member: "…"` | Alternatives; re-declaring an inherited member overrides it. A Hash value is per slot. | | `flag :name, "…"` | On/off modifier. | | `default :group, :member` | Used when the caller names none of the group. | | `compound(**match, class:, set: {})` | Classes (and members for empty groups) when `match` holds. | | `state :name, "variant"` | Names `hover`, `focus-visible`, `[.dropdown[open]>&]`, … | | `on(states, **match, class:)` | Like `compound`, written once per state. | | `slot :name, "…"` | A part. In the component: `slot_classes(:menu, options)` returns its classes (given `class:` last) and removes `class:` from `options`, so call it once per part; `slot_options(:menu, options)` returns `options` carrying them. | A `match` value holds when: | Value | Holds when | |---|---| | `:member` | that member is selected (given, defaulted or set) | | `[:a, :b]` | any is selected; a `nil` in the list means "or none" | | `nil` / `false` | no member of the group is selected | | `true` | any member of the group is selected | | `true` / `false` (flag) | the flag is on / off | A typo (unknown group, member, flag, state or slot) raises `ArgumentError` at class load. ## Render order pitfalls Order: component class, `base`, the caller's modifiers, defaulted and `set:` members, compounds, `on` rules, `responsive:`, then `class:`. ClassMerge keeps the last of any conflicting group. - A **default** renders after the caller's modifiers, so a default member beats a caller's modifier that sets the same property. Put such a value in `base` instead. - **Compounds and `on` rules** also land after the caller's modifiers. When one overrides a property a modifier sets, leave that modifier out of the match (`layout: [nil, :row]`). - `on` writes `<state>:<class>`, the state outermost. A rule that needs a child selector first (`[&_li]:hover:…`) cannot be an `on` rule; keep it literal in `base`. - Don't name a group like an inherited one with a different meaning (`Button` already has `shape`: your members become alternatives of its `circle` and `square`). - A state selector with a child combinator puts `>` inside the class attribute; a spec that matches HTML with `<a[^>]*…>` breaks. Parse with Nokogiri or `rendered.css(…)`. ## Tailwind sources Tailwind v4 compiles only literal classes, and an `on` class (`hover:…`) is written nowhere. Generate the sources and commit them: ```sh bin/rails "daisyui:tailwind[app/assets/stylesheets/generated/daisyui_app.css]" # no Rails: bundle exec daisyui-tailwind --app --require ./components.rb -o <file> ``` - `@import` the file from the Tailwind entry. Workflow's path and entry win over this example. - Add a spec so a changed declaration fails until regenerated: `expect(DaisyUI::Tailwind.stale?(path)).to be(false)`. - Exclude the generated file from the stylesheet linter. - Regenerate after every change to a `variants` block, and commit the file with it. ## Introspection Read what a component already offers before declaring anything. ```ruby Tile.variants.schema # frozen Hash: base, variants, flags, defaults, compounds, on, states, slots Tile.variants.literal_classes ``` The gem's MCP server (`bundle exec daisyui-mcp`) has `list_components`, `get_component` and `search_components`; `get_component` returns the schema too when your gem version has it. Without it, read the component's source in the gem. ## Anti-patterns - A class-string constant (`CLASSES = "btn btn-ghost"`) or a `base_class` override instead of `base`. - A method that reads `modifiers` and picks classes (`modifiers.include?(:loud) ? … : …`): that is a `variant`, `flag` or `compound`. - An interpolated class (`"btn-#{tone}"`, `"hover:#{x}"`): Tailwind cannot see it. Declare each member. - A raw element with the kit's classes (`button(class: "btn …")`); call the wrapper (/rails-app:views). - A feature-named CSS selector for something a `state` and `on` express. - Editing the generated sources file by hand. ## Done when - A component spec renders each new member, default and compound and asserts the classes. - The generated sources are regenerated and committed, and the stale spec passes. - Workflow → Verify passes.
Ver en GitHub