Dstar.Elements (dstar v0.1.5)

Copy Markdown View Source

Functions for patching and removing DOM elements via SSE.

conn |> patch("<div>New content</div>", selector: "#target")
conn |> patch("<p>Inner</p>", selector: "#target", mode: :inner)
conn |> remove("#target")

Summary

Functions

Appends html as the last child of container.

Formats an element patch as an SSE event string (for stateless responses).

Formats an element removal as an SSE event string (for stateless responses).

Patches DOM elements with new HTML content.

Removes elements from the DOM by selector.

Morphs the element whose DOM id matches the root element of html.

Functions

append(conn, html, container, opts \\ [])

Appends html as the last child of container.

The fast path for create-events on a plain, unfiltered feed. If the list is filtered, sorted or paginated, the stream cannot know this tab's view state — use Dstar.Signals.nudge/3 instead. See the Live collections guide.

Example

conn |> Dstar.Elements.append(post_row(%{post: post}), "#posts")

format_patch(html, opts \\ [])

@spec format_patch(
  String.t() | Phoenix.HTML.safe() | nil,
  keyword()
) :: String.t()

Formats an element patch as an SSE event string (for stateless responses).

Example

format_patch("<div id=\"feed\">content</div>")
format_patch("<div>content</div>", selector: "#target")
format_patch("<circle r='10'/>", selector: "#svg", namespace: :svg)

format_remove(selector, opts \\ [])

@spec format_remove(
  String.t(),
  keyword()
) :: String.t()

Formats an element removal as an SSE event string (for stateless responses).

Example

format_remove("#target")
# => "event: datastar-patch-elements\ndata: mode remove\ndata: selector #target\n\n"

patch(conn, html, opts \\ [])

@spec patch(Plug.Conn.t(), String.t() | Phoenix.HTML.safe() | nil, keyword()) ::
  Plug.Conn.t()

Patches DOM elements with new HTML content.

When no :selector is provided, each top-level element in the HTML must have an id attribute so Datastar can target it by ID.

The html argument may be nil when using mode: :remove (elements are not needed for removal).

Options

  • :selector - CSS selector for target elements (optional — defaults to element ID)
  • :mode - Patch mode (default: :outer). Only non-default values are sent.
  • :namespace - Element namespace: :html, :svg, :mathml (default: :html)
  • :use_view_transitions - Enable View Transitions API (default: false)
  • :event_id - Event ID for client tracking
  • :retry - Retry duration in milliseconds

Examples

# Patch by element ID (no selector needed)
conn |> patch("<div id=\"feed\">New content</div>")

# Patch with explicit selector
conn |> patch("<div>Content</div>", selector: "#target")

# Update inner HTML only
conn |> patch("<p>New text</p>", selector: ".content", mode: :inner)

# Append to element
conn |> patch("<li>Item</li>", selector: "ul", mode: :append)

# Remove by selector (no HTML needed)
conn |> patch(nil, selector: "#old", mode: :remove)

# SVG namespace
conn |> patch("<circle cx='50' cy='50' r='40'/>", selector: "#svg", namespace: :svg)

# With view transitions
conn |> patch("<div>Smooth</div>", selector: "#box", use_view_transitions: true)

remove(conn, selector, opts \\ [])

@spec remove(Plug.Conn.t(), String.t(), keyword()) :: Plug.Conn.t()

Removes elements from the DOM by selector.

Sends a datastar-patch-elements event with mode remove.

Options

  • :event_id - Event ID for client tracking
  • :retry - Retry duration in milliseconds

Example

conn
|> Dstar.Elements.remove(".temporary")
|> Dstar.Elements.remove("#old-content")

upsert(conn, html, opts \\ [])

@spec upsert(Plug.Conn.t(), String.t() | Phoenix.HTML.safe(), keyword()) ::
  Plug.Conn.t()

Morphs the element whose DOM id matches the root element of html.

Sends no selector, so Datastar targets by id.

Dropped when absent

If the tab has no element with that id, Datastar logs PatchElementsNoTargetsFound and drops the patch — a row this tab never rendered stays absent. That is fine for a plain feed; when it is not (filtered, sorted or paginated lists), use Dstar.Signals.nudge/3.

Example

conn |> Dstar.Elements.upsert(post_row(%{post: post}))