View Source Surface (surface v0.11.0)

Surface is a component based library for Phoenix LiveView.

Built on top of the new Phoenix.LiveComponent API, Surface provides a more declarative way to express and use components in Phoenix.

Full documentation and live examples can be found at surface-ui.org

This module defines the ~F sigil that should be used to translate Surface code into Phoenix templates.

In order to have ~F available for any Phoenix view, add the following import to your web file in lib/my_app_web.ex:

# lib/my_app_web.ex

...

def view do
  quote do
    ...
    import Surface
  end
end

Additionally, use Surface.init/1 in your mount function to initialize assigns used internally by surface:

# A LiveView using surface templates

defmodule PageLive do
  use Phoenix.LiveView
  import Surface

  def mount(_params, _session, socket) do
    socket = Surface.init(socket)
    ...
    {:ok, socket}
  end

  def render(assigns) do
    ~F"""
    ...
    """
  end
end

# A LiveComponent using surface templates

defmodule NavComponent do
  use Phoenix.LiveComponent
  import Surface

  def mount(socket) do
    socket = Surface.init(socket)
    ...
    {:ok, socket}
  end

  def render(assigns) do
    ~F"""
    ...
    """
  end
end

defining-components

Defining components

To create a component you need to define a module and use one of the available component types:

example

Example

# A functional stateless component

defmodule Button do
  use Surface.Component

  prop click, :event
  prop kind, :string, default: "is-info"

  def render(assigns) do
    ~F"""
    <button class={"button", @kind} :on-click={@click}>
      <#slot/>
    </button>
    """
  end
end

You can visit the documentation of each type of component for further explanation and examples.

Link to this section Summary

Functions

Embeds an .sface template as a function component.

Retrieve all component's config

Retrieve the component's config based on the key

Retrieve a component's config based on the key

Initialize surface state in the socket

Converts the given code into Surface's AST.

Translates Surface code into Phoenix templates.

Tests if a slot has been filled in.

Link to this section Functions

Link to this macro

embed_sface(relative_file)

View Source (macro)

Embeds an .sface template as a function component.

example

Example

defmodule MyAppWeb.Layouts do
  use MyAppWeb, :html

  embed_sface "layouts/root.sface"
  embed_sface "layouts/app.sface"
end

The code above generates two functions, root and app. You can use both as regular function components or as layout templates.

Link to this function

event_to_opts(value, event_name)

View Source

Retrieve all component's config

Link to this macro

get_config(key)

View Source (macro)

Retrieve the component's config based on the key

Link to this function

get_config(component, key)

View Source

Retrieve a component's config based on the key

Initialize surface state in the socket

Link to this macro

quote_surface(opts \\ [], list)

View Source (macro)

Converts the given code into Surface's AST.

The code must be passed with the do block using the ~F sigil.

Optional line, file and caller metadata can be passed using opts.

example

Example

iex> [tag] =
...>   quote_surface do
...>     ~F"<div>content</div>"
...>   end
...>
...> tag.children
[%Surface.AST.Literal{directives: [], value: "content"}]
Link to this macro

sigil_F(arg, opts)

View Source (macro)

Translates Surface code into Phoenix templates.

Link to this macro

slot_assigned?(slot)

View Source (macro)

Tests if a slot has been filled in.

Useful to avoid rendering unnecessary html tags that are used to wrap an optional slot in combination with :if directive.

examples

Examples

  <div :if={slot_assigned?(:header)}>
    <#slot {@header}/>
  </div>