Datastar for Elixir

An Elixir SDK for the Datastar web framework, modeled after the Go implementation.

Datastar enables real-time, server-driven UI updates using Server-Sent Events (SSE). This library provides a clean, idiomatic Elixir interface for streaming dynamic updates to your web applications.

Features

Installation

Add datastar_ex to your list of dependencies in mix.exs:

def deps do
  [
    {:datastar_ex, "~> 0.1.0"}
  ]
end

Quick Start

Basic SSE Streaming

defmodule MyAppWeb.DatastarController do
  use MyAppWeb, :controller
  alias Datastar.{SSE, Elements, Signals}

  def stream(conn, _params) do
    conn
    |> put_resp_content_type("text/event-stream")
    |> send_chunked(200)
    |> SSE.new()
    |> Elements.patch("<div>Hello, Datastar!</div>", selector: "#content")
  end
end

Reading Signals

Signals represent client-side state that can be synchronized with the server:

def handle_request(conn, _params) do
  # Read signals from the request
  signals = Datastar.Signals.read(conn)
  count = signals["count"] || 0

  # Update the UI based on signals
  conn
  |> put_resp_content_type("text/event-stream")
  |> send_chunked(200)
  |> SSE.new()
  |> Signals.patch(%{count: count + 1})
  |> Elements.patch("<div>Count: #{count + 1}</div>", selector: "#counter")
end

Patching Elements

Update DOM elements with various merge strategies:

sse
# Replace entire element (outer HTML)
|> Elements.patch("<div id=&#39;box&#39;>New content</div>", selector: "#box")

# Replace inner HTML only
|> Elements.patch("<p>Inner content</p>", selector: "#container", mode: :inner)

# Append to element
|> Elements.patch("<li>New item</li>", selector: "ul", mode: :append)

# Prepend to element
|> Elements.patch("<li>First item</li>", selector: "ul", mode: :prepend)

# Insert before element
|> Elements.patch("<div>Before</div>", selector: "#target", mode: :before)

# Insert after element
|> Elements.patch("<div>After</div>", selector: "#target", mode: :after)

Removing Elements

sse
|> Elements.remove("#temporary-message")
|> Elements.remove_by_id("old-content")

JavaScript Execution

sse
# Execute arbitrary JavaScript
|> Script.execute("alert(&#39;Hello from server!&#39;)")

# Console logging
|> Script.console_log("Debug message")
|> Script.console_error("Error occurred")

# Navigation
|> Script.redirect("/dashboard")
|> Script.replace_url("/new-path")

# Custom events
|> Script.dispatch_custom_event("user-updated", %{id: 123, name: "Alice"})

# Prefetch URLs
|> Script.prefetch(["/dashboard", "/profile"])

API Reference

Datastar.SSE

Core module for Server-Sent Event streaming:

Datastar.Signals

Manage client-side reactive state:

Options:

Datastar.Elements

Manipulate DOM elements:

Convenience functions:

Options:

Datastar.Script

Execute JavaScript and manage browser state:

Options:

Complete Example

Here's a complete example of a Phoenix LiveView-style counter:

defmodule MyAppWeb.CounterController do
  use MyAppWeb, :controller
  alias Datastar.{SSE, Elements, Signals, Script}

  def increment(conn, _params) do
    # Read current count from client
    signals = Signals.read(conn)
    current_count = signals["count"] || 0
    new_count = current_count + 1

    # Stream updates back
    conn
    |> put_resp_content_type("text/event-stream")
    |> send_chunked(200)
    |> SSE.new()
    |> Signals.patch(%{count: new_count})
    |> Elements.patch(
      "<div>Count: #{new_count}</div>",
      selector: "#counter"
    )
    |> Script.console_log("Count updated to #{new_count}")
  end

  def reset(conn, _params) do
    conn
    |> put_resp_content_type("text/event-stream")
    |> send_chunked(200)
    |> SSE.new()
    |> Signals.patch(%{count: 0})
    |> Elements.patch("<div>Count: 0</div>", selector: "#counter")
    |> Script.dispatch_custom_event("counter-reset", %{})
  end
end

Comparison with Go SDK

This Elixir SDK closely follows the design of the Go implementation, with idiomatic Elixir adaptations:

Requirements

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Resources

Acknowledgments

This SDK is modeled after the excellent Datastar Go SDK by the Star Federation team.