OopsieDaisy
Generate type-safe Phoenix components from DaisyUI documentation.
What is this?
OopsieDaisy automatically creates Phoenix.Component modules for DaisyUI components. Point it at DaisyUI's docs, and it generates clean, production-ready Phoenix components with proper attributes, variants, and type safety.
Instead of manually writing components and keeping them in sync with DaisyUI updates, generate them automatically.
Quick Start
Add to your Phoenix project:
# mix.exs
def deps do
[
{:oopsie_daisy, "~> 0.1.0", only: :dev, runtime: false}
]
endGenerate components:
# From your Phoenix project root
mix oopsie_daisy.gen
# Or generate specific components
mix oopsie_daisy.gen --components button,badge,card
Components are generated in lib/oopsie_daisy_components/ with your app's namespace (e.g., MyAppWeb.Components.Button).
Use in your templates:
<.button variant={:primary} size={:lg}>
Click me
</.button>
<.badge variant={:success}>
New
</.badge>How It Works
- Clones DaisyUI repo (automatically, once)
- Parses markdown documentation to extract HTML examples
- Analyzes CSS classes to detect variants (colors, sizes, styles)
- Generates Phoenix.Component modules with proper
attrdeclarations - Creates helper functions for class composition
Generated Components
Every generated component includes:
- Type-safe attributes with allowed values
- Smart defaults based on DaisyUI
- Helper functions for class composition
-
Support for custom classes via
classattribute -
Pass-through for HTML attributes via
@rest
Example generated component:
defmodule MyAppWeb.Components.Button do
use Phoenix.Component
attr :variant, :atom, default: nil,
values: [nil, :primary, :secondary, :accent, :neutral, :info, :success, :warning, :error]
attr :size, :atom, default: :md,
values: [:xs, :sm, :md, :lg, :xl]
attr :style, :atom, default: nil,
values: [nil, :outline, :ghost, :link]
attr :class, :string, default: ""
attr :rest, :global, include: ~w(disabled type)
slot :inner_block, required: true
def button(assigns) do
~H"""
<button class={["btn", variant_class(@variant), size_class(@size), style_class(@style), @class]} {@rest}>
<%= render_slot(@inner_block) %>
</button>
"""
end
defp variant_class(nil), do: nil
defp variant_class(:primary), do: "btn-primary"
# ... etc
endUsage Examples
Basic components
<.button>Default</.button>
<.button variant={:primary}>Primary</.button>
<.button variant={:error} size={:lg}>Large Error</.button>With custom classes
<.button variant={:primary} class="mt-4 shadow-xl">
Custom styled
</.button>With HTML attributes
<.button variant={:primary} type="submit" disabled={@is_submitting}>
Submit
</.button>Dynamic variants
<.badge variant={@status}>
<%= @status_text %>
</.badge>Configuration
Auto-detection
By default, the generator detects your app name and uses the appropriate namespace:
-
Phoenix app
my_app→MyAppWeb.Components.* -
Other Elixir apps →
MyApp.Components.*
Override defaults
# Custom output directory
mix oopsie_daisy.gen --output-dir lib/my_app_web/custom_components
# Custom module namespace
mix oopsie_daisy.gen --base-module MyApp.UI.Components
# Preview without writing files
mix oopsie_daisy.gen --dry-run
# Skip cloning DaisyUI (if already cloned)
mix oopsie_daisy.gen --skip-cloneRequirements
Your Phoenix app needs:
-
Phoenix 1.7+ (for
Phoenix.Component) - Tailwind CSS configured
- DaisyUI plugin installed and configured
To run the generator:
- Elixir ~> 1.18
- Git (for cloning DaisyUI repo)
The generator itself requires Floki for HTML parsing, but it's only needed at dev time.
DaisyUI Setup
If you haven't set up DaisyUI yet:
# Install DaisyUI
cd assets
npm install -D daisyui@latest// assets/tailwind.config.js
module.exports = {
plugins: [
require("daisyui")
],
daisyui: {
themes: ["light", "dark"], // or your custom themes
},
}When to Use This
Good fit:
- You're building a Phoenix app with DaisyUI
- You want type-safe component APIs
- You want to keep components in sync with DaisyUI updates
- You prefer Phoenix.Component patterns over raw HTML/CSS classes
Not needed if:
- You're happy writing DaisyUI classes directly in HEEx
- You only use a handful of components
- You have highly customized component APIs
Programmatic API
Generate components from Elixir code:
# Generate all components
{:ok, results} = OopsieDaisy.generate()
# Generate specific components
{:ok, results} = OopsieDaisy.generate(
components: ["button", "badge"],
output_dir: "lib/my_app_web/components"
)
# Override module namespace
{:ok, results} = OopsieDaisy.generate(
base_module: "MyApp.Components"
)Updating Components
When DaisyUI updates:
# Remove cloned repo
rm -rf tmp/daisyui
# Re-generate components
mix oopsie_daisy.genThe generator will clone the latest DaisyUI and regenerate all components.
License
CC0 1.0 Universal - Public Domain
Use this however you want.
Credits
- Built with Claude Code
- Extracted from Boxy
- Generates components for DaisyUI