Helpers for generating Datastar action expressions and encoding module names.
Examples
# In a Phoenix template:
<button data-on:click={Dstar.post(MyApp.CounterHandler, "increment")}>+</button>
# Other HTTP verbs:
<button data-on:click={Dstar.delete(MyApp.ItemHandler, "remove")}>×</button>
# Dynamic module (reads from signal):
<button data-on:click={Dstar.post("increment")}>+</button>Literal event and module values are percent-encoded as one URL path segment. Dynamic module signals are encoded in the browser. Exact empty and dot segments are rejected because browser URL parsing would remove or normalize them.
A :prefix, when supplied to a module form, must be a local absolute
application path: it starts with one / and contains no dot segment,
backslash, query, fragment, or control character. "" means no prefix.
Summary
Functions
Decodes a URL-safe module name back to an Elixir module.
Generates a @delete(...) action expression for Datastar attributes.
Generates a @delete(...) expression with a local absolute URL prefix.
Encodes a module name for URL use.
Generates a @get(...) action expression for Datastar attributes.
Generates a @get(...) expression with a local absolute URL prefix.
Runs action whenever Dstar.Signals.nudge/3 bumps key.
Generates a @patch(...) action expression for Datastar attributes.
Generates a @patch(...) expression with a local absolute URL prefix.
Generates a @post(...) action expression for Datastar attributes.
Generates a @post(...) expression with a local absolute URL prefix.
Generates a @put(...) action expression for Datastar attributes.
Generates a @put(...) expression with a local absolute URL prefix.
Functions
Decodes a URL-safe module name back to an Elixir module.
Returns {:ok, module} if the module exists, :error otherwise.
Examples
iex> Dstar.Actions.decode_module("my_app-counter_view")
{:ok, MyApp.CounterView}
Generates a @delete(...) action expression for Datastar attributes.
CSRF is handled automatically — Datastar sends all signals (including
csrf) as body params on POST/PUT/PATCH and in the datastar query
parameter on GET/DELETE; RenameCsrfParam maps it to _csrf_token.
With a known module (compile-time):
iex> Dstar.Actions.delete(MyApp.CounterHandler, "increment")
~s|@delete("/ds/my_app-counter_handler/increment")|With a dynamic module signal (runtime on client):
iex> expression = Dstar.Actions.delete("increment")
iex> String.contains?(expression, "encodeURIComponent")
trueWith a URL prefix:
iex> Dstar.Actions.delete(MyApp.Handler, "save", prefix: "/ws")
~s|@delete("/ws/ds/my_app-handler/save")|Options
:prefix— local absolute application path (for example,"/my-workspace"). Only for the module form; relative, protocol-relative, cross-origin, dot-segment, query, fragment, backslash, and control-containing values are rejected; percent escapes must decode as valid UTF-8.""is the same as omitting it.:module— literal module override. Only for the dynamic form. Without it, the$_dstar_modulesignal is read and encoded at runtime.
Event and module values are encoded as one literal route segment. Empty,
".", and ".." values raise ArgumentError because browsers normalize
those segments.
Generates a @delete(...) expression with a local absolute URL prefix.
The prefix must start with one / and cannot contain a dot segment,
backslash, query, fragment, or control character. Percent escapes must be
valid UTF-8.
Example
iex> Dstar.Actions.delete(MyApp.Handler, "save", prefix: "/my-workspace")
~s|@delete("/my-workspace/ds/my_app-handler/save")|
Encodes a module name for URL use.
Examples
iex> Dstar.Actions.encode_module(MyApp.CounterView)
"my_app-counter_view"
iex> Dstar.Actions.encode_module(MyApp.Web.ChatView)
"my_app-web-chat_view"
Generates a @get(...) action expression for Datastar attributes.
CSRF is handled automatically — Datastar sends all signals (including
csrf) as body params on POST/PUT/PATCH and in the datastar query
parameter on GET/DELETE; RenameCsrfParam maps it to _csrf_token.
With a known module (compile-time):
iex> Dstar.Actions.get(MyApp.CounterHandler, "increment")
~s|@get("/ds/my_app-counter_handler/increment")|With a dynamic module signal (runtime on client):
iex> expression = Dstar.Actions.get("increment")
iex> String.contains?(expression, "encodeURIComponent")
trueWith a URL prefix:
iex> Dstar.Actions.get(MyApp.Handler, "save", prefix: "/ws")
~s|@get("/ws/ds/my_app-handler/save")|Options
:prefix— local absolute application path (for example,"/my-workspace"). Only for the module form; relative, protocol-relative, cross-origin, dot-segment, query, fragment, backslash, and control-containing values are rejected; percent escapes must decode as valid UTF-8.""is the same as omitting it.:module— literal module override. Only for the dynamic form. Without it, the$_dstar_modulesignal is read and encoded at runtime.
Event and module values are encoded as one literal route segment. Empty,
".", and ".." values raise ArgumentError because browsers normalize
those segments.
Generates a @get(...) expression with a local absolute URL prefix.
The prefix must start with one / and cannot contain a dot segment,
backslash, query, fragment, or control character. Percent escapes must be
valid UTF-8.
Example
iex> Dstar.Actions.get(MyApp.Handler, "save", prefix: "/my-workspace")
~s|@get("/my-workspace/ds/my_app-handler/save")|
Runs action whenever Dstar.Signals.nudge/3 bumps key.
Returns an attribute map for HEEx spread:
<div id="posts" {on_nudge("posts", event("reload"))}>Unlike data-effect, this does not fire on page init — only when that
one nudge changes. See the Live collections guide.
Examples
iex> Dstar.Actions.on_nudge("posts", "@post('/reload')")
%{
"data-on-signal-patch" => "@post('/reload')",
"data-on-signal-patch-filter" => ~S({"include":"^nudges\\.posts$"})
}
Generates a @patch(...) action expression for Datastar attributes.
CSRF is handled automatically — Datastar sends all signals (including
csrf) as body params on POST/PUT/PATCH and in the datastar query
parameter on GET/DELETE; RenameCsrfParam maps it to _csrf_token.
With a known module (compile-time):
iex> Dstar.Actions.patch(MyApp.CounterHandler, "increment")
~s|@patch("/ds/my_app-counter_handler/increment")|With a dynamic module signal (runtime on client):
iex> expression = Dstar.Actions.patch("increment")
iex> String.contains?(expression, "encodeURIComponent")
trueWith a URL prefix:
iex> Dstar.Actions.patch(MyApp.Handler, "save", prefix: "/ws")
~s|@patch("/ws/ds/my_app-handler/save")|Options
:prefix— local absolute application path (for example,"/my-workspace"). Only for the module form; relative, protocol-relative, cross-origin, dot-segment, query, fragment, backslash, and control-containing values are rejected; percent escapes must decode as valid UTF-8.""is the same as omitting it.:module— literal module override. Only for the dynamic form. Without it, the$_dstar_modulesignal is read and encoded at runtime.
Event and module values are encoded as one literal route segment. Empty,
".", and ".." values raise ArgumentError because browsers normalize
those segments.
Generates a @patch(...) expression with a local absolute URL prefix.
The prefix must start with one / and cannot contain a dot segment,
backslash, query, fragment, or control character. Percent escapes must be
valid UTF-8.
Example
iex> Dstar.Actions.patch(MyApp.Handler, "save", prefix: "/my-workspace")
~s|@patch("/my-workspace/ds/my_app-handler/save")|
Generates a @post(...) action expression for Datastar attributes.
CSRF is handled automatically — Datastar sends all signals (including
csrf) as body params on POST/PUT/PATCH and in the datastar query
parameter on GET/DELETE; RenameCsrfParam maps it to _csrf_token.
With a known module (compile-time):
iex> Dstar.Actions.post(MyApp.CounterHandler, "increment")
~s|@post("/ds/my_app-counter_handler/increment")|With a dynamic module signal (runtime on client):
iex> expression = Dstar.Actions.post("increment")
iex> String.contains?(expression, "encodeURIComponent")
trueWith a URL prefix:
iex> Dstar.Actions.post(MyApp.Handler, "save", prefix: "/ws")
~s|@post("/ws/ds/my_app-handler/save")|Options
:prefix— local absolute application path (for example,"/my-workspace"). Only for the module form; relative, protocol-relative, cross-origin, dot-segment, query, fragment, backslash, and control-containing values are rejected; percent escapes must decode as valid UTF-8.""is the same as omitting it.:module— literal module override. Only for the dynamic form. Without it, the$_dstar_modulesignal is read and encoded at runtime.
Event and module values are encoded as one literal route segment. Empty,
".", and ".." values raise ArgumentError because browsers normalize
those segments.
Generates a @post(...) expression with a local absolute URL prefix.
The prefix must start with one / and cannot contain a dot segment,
backslash, query, fragment, or control character. Percent escapes must be
valid UTF-8.
Example
iex> Dstar.Actions.post(MyApp.Handler, "save", prefix: "/my-workspace")
~s|@post("/my-workspace/ds/my_app-handler/save")|
Generates a @put(...) action expression for Datastar attributes.
CSRF is handled automatically — Datastar sends all signals (including
csrf) as body params on POST/PUT/PATCH and in the datastar query
parameter on GET/DELETE; RenameCsrfParam maps it to _csrf_token.
With a known module (compile-time):
iex> Dstar.Actions.put(MyApp.CounterHandler, "increment")
~s|@put("/ds/my_app-counter_handler/increment")|With a dynamic module signal (runtime on client):
iex> expression = Dstar.Actions.put("increment")
iex> String.contains?(expression, "encodeURIComponent")
trueWith a URL prefix:
iex> Dstar.Actions.put(MyApp.Handler, "save", prefix: "/ws")
~s|@put("/ws/ds/my_app-handler/save")|Options
:prefix— local absolute application path (for example,"/my-workspace"). Only for the module form; relative, protocol-relative, cross-origin, dot-segment, query, fragment, backslash, and control-containing values are rejected; percent escapes must decode as valid UTF-8.""is the same as omitting it.:module— literal module override. Only for the dynamic form. Without it, the$_dstar_modulesignal is read and encoded at runtime.
Event and module values are encoded as one literal route segment. Empty,
".", and ".." values raise ArgumentError because browsers normalize
those segments.
Generates a @put(...) expression with a local absolute URL prefix.
The prefix must start with one / and cannot contain a dot segment,
backslash, query, fragment, or control character. Percent escapes must be
valid UTF-8.
Example
iex> Dstar.Actions.put(MyApp.Handler, "save", prefix: "/my-workspace")
~s|@put("/my-workspace/ds/my_app-handler/save")|