View Source

Petal Components

About 🌺

Petal stands for:

Petal is a set of HEEX components that makes it easy for Phoenix developers to start building beautiful web apps.

Docs 📄

Install

For Petal to work you simply need Tailwind CSS and Alpine JS installed along with with some Tailwind configuration.

Existing projects

1 - Follow this guide to install Tailwind and Alpine.

2 - Add Petal to your deps:

mix.exs

defp deps do
  [
    {:petal_components, "~> 0.3.0"},
  ]
end

3 - Modify your tailwind.config.js file to include these settings:

const colors = require("tailwindcss/colors");

module.exports = {
  mode: "jit",
  purge: [
    "../lib/*_web/**/*.*ex",
    "./js/**/*.js",

    // We need to include the Petal dependency so the classes get picked up by JIT.
    "../deps/petal_components/**/*.*ex"
  ],
  darkMode: false,
  theme: {
    extend: {

      // Set these to your brand colors
      colors: {
        primary: colors.blue,
        secondary: colors.pink,
      },
    },
  },
  plugins: [require("@tailwindcss/forms")],
};

4 - Alias the components in your <your_project>_web.ex file

defmodule YourProjectWeb
  ...

  defp view_helpers do
    quote do
      ...

      use PetalComponents
    end
  end

This will import the functions so you can go <.button /> in your templates / live views.

If the function names clash with yours (eg. you already have a .button function) you can opt to alias the modules instead:

defmodule YourProjectWeb
  ...

  defp view_helpers do
    quote do
      ...

      alias PetalComponents.{
        Heroicons,
        Alert,
        Badge,
        Button,
        Container,
        Dropdown,
        Form,
        Loading,
        Typography
      }
    end
  end

New projects

We recommend using Petal boilerplate, which is a fresh Phoenix install with Tailwind + Alpine installed. It comes with a project renaming script so you can still rename your project to whatever you like.

Roadmap

Layout

  • [x] container

Form components

  • [x] text input
  • [x] select dropdown
  • [x] textarea
  • [x] checkbox
  • [ ] multiple select
  • [x] radios
  • [ ] file upload
  • [ ] switch

Buttons

  • [x] basic button
  • [x] change size
  • [x] change color
  • [x] loading state (with spinner)
  • [x] filled vs outline
  • [ ] button group

Misc

  • [x] menu dropdown
  • [ ] tooltips
  • [ ] avatar
  • [x] alerts
  • [ ] tables
  • [ ] cards
  • [ ] breadcrumbs
  • [ ] modal
  • [ ] slide over
  • [ ] spinners
  • [ ] accordian
  • [ ] pagination
  • [x] badges

Examples

Containers

<Container.container max_width="full | lg | md | sm">

Buttons

Button types

<.button label="Button">
<.a href="/" label="a">
<.patch href="/" label="Live Patch">
<.redirect href="/" label="Live Redirect">

Button colors

<.button color="primary | secondary | white | success | danger" label="Primary" />

Button colors (outline)

<.button color="primary | secondary | white | success | danger" label="Primary" variant="outline" />

Button sizes

<.button size="sm | md | lg | xl">

Button states

Disabled
<.button disabled type="a" href="/" label="a Disabled" />
<.button disabled color="primary" label="Button Disabled" />
<.patch disabled href="/" label="Live Patch Disabled" />
<.redirect disabled href="/" label="Live Redirect" />
Loading
<.button loading type="a" href="/" label="a Loading" />
<.button loading label="Button Loading" />
<.patch loading href="/" label="Live Patch Loading" />
<.redirect loading href="/" label="Live Redirect Loading" />

Button with icon

<.button icon type="a" href="/">
  <Heroicons.Solid.home class="w-5 h-5" />
  a with label
</.button>

Typography

<.h1>Heading 1</.h1>
<.h2>Heading 2</.h2>
<.h3>Heading 3</.h3>
<.h4>Heading 4</.h4>
<.h5>Heading 5</.h5>

Heroicons

Heroicons solid

<Heroicons.Solid.home class="w-6 h-6 text-blue-500" />
<Heroicons.Solid.render icon={:home} />

Heroicons outline

<Heroicons.Outline.home class="w-6 h-6 text-blue-500" />
<Heroicons.Outline.render icon={:home} />

Badges

<.badge color="primary | secondary | White | Black | Green | Red | Blue | Gray | Light Gray | Pink | Purple | Orange | Yellow" label="Primary" />

Alerts

Info alert

<.alert state="info">
  This is an info state
</.alert>

Success alert

<.alert state="success" label="This is a success state" />

Warning alert

<.alert state="warning" label="This is a warning state" />

Danger alert

<.alert state="danger" label="This is a danger state" />

Forms

Text input

<.text_input form={:user} field={:name} placeholder="eg. John" />

<!-- With a label and bottom margin -->
<div class="mb-6">
  <.form_label form={:user} field={:last_name} />
  <.text_input form={:user} field={:last_name} placeholder="eg. Smith" />
</div>

<!-- Includes label and bottom margin -->
<.form_field
  type="text_input"
  form={:user}
  field={:first_name}
/>

Text area

<.textarea form={:user} field={:description} />

<!-- With a label and bottom margin -->
<div class="mb-6">
  <.form_label form={:user} field={:description} />
  <.textarea form={:user} field={:description} />
</div>

<!-- Includes label and bottom margin -->
<.form_field
  type="textarea"
  form={:user}
  field={:description}
/>

Select

<.select
  options={["Admin": "admin", "User": "user"]}
  form={:user}
  field={:role}
/>

<!-- With a label and bottom margin -->
<div class="mb-6">
  <.form_label form={:user} field={:role} />
  <.select
    options={["Admin": "admin", "User": "user"]}
    form={:user}
    field={:role}
  />
</div>

<!-- Includes label and bottom margin -->
<.form_field
  type="select"
  form={:user}
  field={:first_name}
  options={["Admin": "admin", "User": "user"]}
/>

Checkbox

<!-- Includes the label and margin automatically -->
<.checkbox
  form={:user}
  field={:read_terms}
  label="I accept"
/>

Radios

<!-- A collection of radios - provide options like a select dropdown -->
<.radios
  form={:user}
  field={:eye_color}
  options={["Green": "green", "Blue": "blue", "Gray": "gray"]}
/>
<.dropdown label="Dropdown">
  <.dropdown_menu_item type="button">
    <Heroicons.Outline.home class="w-5 h-5 text-gray-500" />
    Button item with icon
  </.dropdown_menu_item>
  <.dropdown_menu_item type="a" href="/" label="a item" />
  <.dropdown_menu_item type="live_patch" href="/" label="Live Patch item" />
  <.dropdown_menu_item type="live_redirect" href="/" label="Live Redirect item" />
</.dropdown>

Loading indicators

<.spinner show={false} />
<.spinner show={true} size="sm" />
<.spinner show={true} size="md" class="text-green-500" />
<.spinner show={true} size="lg" class="text-red-500" />