# Recursive surface component?

**URL:** <https://forum.elixirforum.com/t/recursive-surface-component/39019>\
**Category:** Discussions\
**Tags:** phoenix, liveview, surface\
**Created:** [April 17, 2021, 12:08am UTC](https://forum.elixirforum.com/t/recursive-surface-component/39019 "2021-04-17T00:08:18Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![derek-zhou](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/derek-zhou/32/19943_2.png) [@derek-zhou](https://forum.elixirforum.com/u/derek-zhou)\
**Post date:** [April 17, 2021, 12:08am UTC](https://forum.elixirforum.com/t/recursive-surface-component/39019/1 "2021-04-17T00:08:18Z")

</div>

Is it possible to have a Surface component that instantiates itself from within (conditionally, of course)  
I was trying to do this in `mail_node.sface`:

```elixir
        <MailNode :for={{ id <- MailClient.children(@mail_client, @id) }}
                  props={{ id: id,                                            
                       meta: MailClient.mail_meta(@mail_client, id),             
                       mail_client: @mail_client }} />

```

Ant it complains:

```elixir
** (CompileError) lib/liv_web/live/mail_node.sface:8: you are trying to use the module LivWeb.MailNode which is currently being defined.

```

If this is not possible, how do I model a recursive data structure like a tree with surface component?

---

<div class="post-metadata">

**Author:** ![msaraiva](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/msaraiva/32/1214_2.png) [@msaraiva](https://forum.elixirforum.com/u/msaraiva)\
**Post date:** [April 17, 2021, 1:11am UTC](https://forum.elixirforum.com/t/recursive-surface-component/39019/2 "2021-04-17T01:11:57Z")

</div>

Hi @derek-zhou!

Currently, Surface does not allow using a component recursively. However, you can work around this issue by moving the recursion to a separate function. For instance:

```elixir
defmodule Tree do
  ...
    
  @doc "The root node"
  prop node, :map
  
  def render(assigns) do
    ~H"""
    {{ render_node(@node) }}
    """
  end

  defp render_node(node) do
    ~H"""
    <div>
      {{ node.name }}
      <div :for={{ child <- node.children }}>
        {{ render_node(child) }}
      </div>
    </div>
    """
  end
end

```

---

<div class="post-metadata">

**Author:** ![derek-zhou](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/derek-zhou/32/19943_2.png) [@derek-zhou](https://forum.elixirforum.com/u/derek-zhou)\
**Post date:** [April 17, 2021, 1:37am UTC](https://forum.elixirforum.com/t/recursive-surface-component/39019/3 "2021-04-17T01:37:15Z")

</div>

Thanks. I will try this and the other venue I am trying, which is to use a MacroComponent that hide the recursion inside.

---

<div class="post-metadata">

**Author:** ![derek-zhou](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/derek-zhou/32/19943_2.png) [@derek-zhou](https://forum.elixirforum.com/u/derek-zhou)\
**Post date:** [April 17, 2021, 2:54pm UTC](https://forum.elixirforum.com/t/recursive-surface-component/39019/4 "2021-04-17T14:54:56Z")

</div>

@msaraiva 's example can be simplified to:

```elixir
defmodule Tree do
  ...
    
  @doc "The root node"
  prop node, :map
  
  def render(assigns) do
    ~H"""
    <div>
      {{ @node.name }}
      <div :for={{ child <- @node.children }}>
        {{ render(%{node: child}) }}
      </div>
    </div>
    """
  end
end

```

Although the component cannot be recursively defined, the `render/1` method can call itself recursively, with a made up assigns. This method works as long as the component has no state; because state-less component is basically just a `render/1` function with maybe some pure function helpers.

I don’t know how to achieve the equivalent of recursive stateful component though. I don’t have a usage case so far.

---

<div class="post-metadata">

**Author:** ![derek-zhou](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/derek-zhou/32/19943_2.png) [@derek-zhou](https://forum.elixirforum.com/u/derek-zhou)\
**Post date:** [April 22, 2021, 7:21pm UTC](https://forum.elixirforum.com/t/recursive-surface-component/39019/5 "2021-04-22T19:21:23Z")

</div>

Note: If you are going to call `render/1` manually with a made up assigns like above, it is best to pass in @socket too, like `{{ render(%{socket: @socket, node: child}) }}` The reason is components pass @socket implicitly, and many things need @socket; so without the @socket in the assigns it can be very confusing.
