Temple.Component (Temple v0.6.1) View Source

API for defining components.

Component modules are basically normal Phoenix View modules. The contents of the render macro are compiled into a render/2 function. This means that you can define functions in your component module and use them in your component markup.

Since component modules are view modules, the assigns you pass to the component are accessible via the @ macro and the assigns variable.

You must require Temple.Component in your views that use components, as the c and slot generate markup that uses macros provided by Temple.

Components

defmodule MyAppWeb.Components.Flash do
  import Temple.Component

  def border_class(:info), do: "border-blue-500"
  def border_class(:warning), do: "border-yellow-500"
  def border_class(:error), do: "border-red-500"
  def border_class(:success), do: "border-green-500"

  render do
    div class: "border rounded p-2 #{assigns[:class]} #{border_class(@message_type)}" do
      slot :default
    end
  end
end

Components are used by calling the c keyword, followed by the component module and any assigns you need to pass to the template.

c is a compile time keyword, not a function or a macro, so you won't see it in the generated documention.

c MyAppWeb.Components.Flash, class: "font-bold", message_type: :info do
  ul do
    for info <- infos do
      li class: "p-4" do
        info.message
      end
    end
  end
end

Since components are just modules, if you alias your module, you can use them more ergonomically.

# lib/my_app_web/views/page_view.ex
alias MyAppWeb.Components.Flex

# lib/my_app_web/templates/page/index.html.exs
c Flex, class: "justify-between items center" do
  for item <- items do
    div class: "p-4" do
      item.name
    end
  end
end

Slots

Components can use slots, which are named placeholders for markup that can be passed to the component by the caller.

Slots are invoked by using the slot keyword, followed by the name of the slot and any assigns you'd like to pass into the slot.

slot is a compile time keyword, not a function or a macro, so you won't see it in the generated documention.

defmodule Flex do
  import Temple.Component

  render do
    div class: "flex #{@class}" do
      slot :default
    end
  end
end

You can also use "named slots", which allow for data to be passed back into them. This is very useful when a component needs to pass data from the inside of the component back to the caller, like when rendering a form in LiveView.

defmodule Form do
  import Temple.Component

  render do
    form = form_for(@changeset, @action, assigns)

    form

    slot :f, form: form

    "</form>"
  end
end

By default, the body of a component fills the :default slot.

Named slots can be defined by invoking the slot keyword with the name of the slot and a do block.

You can also pattern match on any assigns that are being passed into the slot as if you were defining an anonymous function.

slot is a compile time keyword, not a function or a macro, so you won't see it in the generated documention.

# lib/my_app_web/templates/post/new.html.lexs

c Form, changeset: @changeset,
        action: @action,
        class: "form-control",
        phx_submit: :save,
        phx_change: :validate do
  slot :f, %{form: f} do
    label f do
      "Widget Name"
      text_input f, :name, class: "text-input"
    end

    submit "Save!"
  end
end

Link to this section Summary

Functions

Defines a component module.

Defines a component template.

Link to this section Functions

Link to this macro

defcomp(module, block)

View Source (macro)

Defines a component module.

This macro makes it easy to define components without creating a separate file. It literally inlines a component module.

Since it defines a module inside of the current module, local function calls from the outer module won't be available. For convenience, the outer module is aliased for you, so you can call remote functions with a shorter module name.

Usage

def MyAppWeb.SomeView do
  use MyAppWeb.SomeView, :view
  import Temple.Component, only: [defcomp: 2]

  # define a function in outer module
  def foobar(), do: "foobar"

  # define a component
  defcomp Button do
    button id: SomeView.foobar(), # `MyAppWeb.SomeView` is aliased for you.
           class: "text-sm px-3 py-2 rounded #{assigns[:extra_classes]}",
           type: "submit" do
      slot :default
    end
  end
end

# use the component in a SomeView template. Or else, you must alias `MyAppWeb.SomeView.Button`
c Button, extra_classes: "border-2 border-red-500" do
  "Submit!"
end

Defines a component template.

Usage

defmodule MyAppWeb.Components.Flash do
  import Temple.Component

  def border_class(:info), do: "border-blue-500"
  def border_class(:warning), do: "border-yellow-500"
  def border_class(:error), do: "border-red-500"
  def border_class(:success), do: "border-green-500"

  render do
    div class: "border rounded p-2 #{assigns[:class]} #{border_class(@message_type)}" do
      slot :default
    end
  end
end