Props & data

Custom Encoder

@derive decides what a struct sends to the client, and what it doesn't

  • @derive LiveReact.Encoder
  • except:

Key concepts

LiveReact's default LiveReact.Encoder implementation for a plain struct sends every field. @derive {LiveReact.Encoder, except: [:api_token]} overrides that per struct, deciding once, in one place, what that struct is allowed to send — every call site that passes it as a prop gets the same guarantee, with nothing to remember or repeat.

encoder_live.ex
defmodule MyAppWeb.EncoderLive.DemoUser do
  @derive {LiveReact.Encoder, except: [:api_token]}
  defstruct [:name, :email, :api_token]
end

defmodule MyAppWeb.EncoderLive do
  use MyAppWeb, :live_view

  alias MyAppWeb.EncoderLive.DemoUser

  def mount(_params, _session, socket) do
    user = %DemoUser{
      name: "Ada Lovelace",
      email: "ada@example.com",
      api_token: "super-secret-never-sent"
    }

    {:ok, assign(socket, :user, user)}
  end

  def render(assigns) do
    ~H"""
    <.react name="Encoder" user={@user} socket={@socket} />
    """
  end
end

How it works

The component below renders exactly what it received — there is no filtering on the React side, and none in the preview's render/1 either. The excepted field is absent from the serialised payload because the encoder never emits it, not because something downstream hides it. Open this page's source and search data-propsapi_token isn't in there, and neither is its value.

except: has a counterpart, only:, for the opposite shape: an allowlist instead of a denylist. Either way, the struct's definition is the one place this decision lives.