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}
  ]
end

Generate 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

  1. Clones DaisyUI repo (automatically, once)
  2. Parses markdown documentation to extract HTML examples
  3. Analyzes CSS classes to detect variants (colors, sizes, styles)
  4. Generates Phoenix.Component modules with proper attr declarations
  5. Creates helper functions for class composition

Generated Components

Every generated component includes:

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
end

Usage 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:

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-clone

Requirements

Your Phoenix app needs:

To run the generator:

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:

Not needed if:

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.gen

The generator will clone the latest DaisyUI and regenerate all components.

License

CC0 1.0 Universal - Public Domain

Use this however you want.

Credits