View Source LiveViewNative.LVN (live_view_native v0.4.0-rc.0)
Provides commands for executing Native utility operations on the client.
LVN commands support a variety of utility operations for common client-side needs, such as adding or removing CSS classes, setting or removing tag attributes, showing or hiding content, and transitioning in and out with animations. While these operations can be accomplished via client-side hooks, LVN commands are ViewTree-patch aware, so operations applied by the LVN APIs will stick to elements across patches from the server.
In addition to purely client-side utilities, the LVN commands include a
rich push
API, for extending the default phx-
binding pushes with
options to customize targets, loading states, and additional payload values.
Client Utility Commands
The following utilities are included:
add_class
- Add classes to elements, with optional transitionsremove_class
- Remove classes from elements, with optional transitionstoggle_class
- Sets or removes classes from elements, with optional transitionsset_attribute
- Set an attribute on elementsremove_attribute
- Remove an attribute from elementstoggle_attribute
- Sets or removes element attribute based on attribute presence.show
- Show elements, with optional transitionshide
- Hide elements, with optional transitionstoggle
- Shows or hides elements based on visibility, with optional transitionstransition
- Apply a temporary transition to elements for animationsdispatch
- Dispatch a ViewTree event to elements
For example, the following modal component can be shown or hidden on the client without a trip to the server:
alias LiveViewNative.LVN
def hide_modal(lvn \\ %LVN{}) do
lvn
|> LVN.hide(transition: "fade-out", to: "#modal")
|> LVN.hide(transition: "fade-out-scale", to: "#modal-content")
end
def modal(assigns) do
~LVN"""
<Text id="modal" class="phx-modal" phx-remove={hide_modal()}>
<Text
id="modal-content"
class="phx-modal-content"
phx-click-away={hide_modal()}
phx-window-keydown={hide_modal()}
phx-key="escape"
>
<Button class="phx-modal-close" phx-click={hide_modal()}>✖</Button>
<Text>{@text}</Text>
</Text>
</Text>
"""
end
Enhanced push events
The push/1
command allows you to extend the built-in pushed event handling
when a phx-
event is pushed to the server. For example, you may wish to
target a specific component, specify additional payload values to include
with the event, apply loading states to external elements, etc. For example,
given this basic phx-click
event:
<Button phx-click="inc">+</Button>
Imagine you need to target your current component, and apply a loading state to the parent container while the client awaits the server acknowledgement:
alias LiveViewNative.LVN
~LVN"""
<Button phx-click={LVN.push("inc", loading: ".thermo", target: @myself)}>+</Button>
"""
Push commands also compose with all other utilities. For example, to add a class when pushing:
<Button phx-click={
LVN.push("inc", loading: ".thermo", target: @myself)
|> LVN.add_class("warmer", to: ".thermo")
}>+</Button>
Any phx-value-*
attributes will also be included in the payload, their
values will be overwritten by values given directly to push/1
. Any
phx-target
attribute will also be used, and overwritten.
<Button
phx-click={LVN.push("inc", value: %{limit: 40})}
phx-value-room="bedroom"
phx-value-limit="this value will be 40"
phx-target={@myself}
>+</Button>
Custom LVN events with LVN.dispatch/1
and window.addEventListener
dispatch/1
can be used to dispatch custom Native events to
elements. For example, you can use LVN.dispatch("click", to: "#foo")
,
to dispatch a click event to an element.
This also means you can augment your elements with custom events,
by using Native's window.addEventListener
and invoking them
with dispatch/1
. For example, imagine you want to provide
a copy-to-clipboard functionality in your application. You can
add a custom event for it:
TODO replace with native version
window.addEventListener("my_app:clipcopy", (event) => {
if ("clipboard" in navigator) {
const text = event.target.textContent;
navigator.clipboard.writeText(text);
} else {
alert("Sorry, your browser does not support clipboard copy.");
}
});
Now you can have a Button like this:
<Button phx-click={LVN.dispatch("my_app:clipcopy", to: "#element-with-text-to-copy")}>
Copy content
</Button>
The combination of dispatch/1
with window.addEventListener
is
a powerful mechanism to increase the amount of actions you can trigger
client-side from your LiveView code.
Summary
Functions
Adds classes to elements.
Combines two JS commands, appending the second to the first.
Dispatches an event to the ViewTree.
Executes LVN commands located in an element's attribute.
See exec/1
.
Sends focus to a selector.
See focus/1
.
Sends focus to the first focusable child in selector.
Hides elements.
See hide/1
.
Sends a navigation event to the server and updates the browser's pushState history.
Sends a patch event to the server and updates the browser's pushState history.
See patch/1
.
Focuses the last pushed element.
Pushes an event to the server.
See push/1
.
Pushes focus from the source element to be later popped.
Removes an attribute from elements.
Removes classes from elements.
Sets an attribute on elements.
Shows elements.
See show/1
.
Toggles element visibility.
Sets or removes element attribute based on attribute presence.
Adds or removes element classes based on presence.
Transitions elements.
Functions
Adds classes to elements.
names
- A string with one or more class names to add.
Options
:to
- An optional ViewTree selector to add classes to. Defaults to the interacted element.:transition
- A string of classes to apply before adding classes or a 3-tuple containing the transition class, the class to apply to start the transition, and the ending transition class, such as:{"ease-out duration-300", "opacity-0", "opacity-100"}
:time
- The time in milliseconds to apply the transition from:transition
. Defaults to 200.
Examples
<Text id="item">My Item</Text>
<Button phx-click={LVN.add_class("highlight underline", to: "#item")}>
highlight!
</Button>
See add_class/1
.
See add_class/1
.
Combines two JS commands, appending the second to the first.
Dispatches an event to the ViewTree.
event
- The string event name to dispatch.
Note: All events dispatched are of a type
CustomEvent,
with the exception of "click"
. For a "click"
, a
MouseEvent
is dispatched to properly simulate a UI click.
For emitted CustomEvent
's, the event detail will contain a dispatcher
,
which references the ViewTree node that dispatched the LVN event to the target
element.
Options
:to
- An optional ViewTree selector to dispatch the event to. Defaults to the interacted element.:detail
- An optional detail map to dispatch along with the client event. The details will be available in theevent.detail
attribute for event listeners.:bubbles
– A boolean flag to bubble the event or not. Defaults totrue
.
Examples
# TODO: replace with native example
window.addEventListener("click", e => console.log("clicked!", e.detail))
<Button phx-click={LVN.dispatch("click", to: ".nav")}>Click me!</Button>
See dispatch/2
.
Executes LVN commands located in an element's attribute.
attr
- The string attribute where the LVN command is specified
Options
:to
- An optional ViewTree selector to fetch the attribute from. Defaults to the current element.
Examples
<Text id="modal" phx-remove={LVN.hide("#modal")}>...</Text>
<Button phx-click={LVN.exec("phx-remove", to: "#modal")}>close</Button>
See exec/1
.
See exec/1
.
Sends focus to a selector.
Options
:to
- An optional ViewTree selector to send focus to. Defaults to the current element.
Examples
LVN.focus(to: "main")
See focus/1
.
Sends focus to the first focusable child in selector.
Options
:to
- An optional ViewTree selector to focus. Defaults to the current element.
Examples
LVN.focus_first(to: "#modal")
See focus_first/1
.
Hides elements.
Options
:to
- An optional ViewTree selector to hide. Defaults to the interacted element.:transition
- A string of classes to apply before hiding or a 3-tuple containing the transition class, the class to apply to start the transition, and the ending transition class, such as:{"ease-out duration-300", "opacity-100", "opacity-0"}
:time
- The time in milliseconds to apply the transition from:transition
. Defaults to 200.
During the process, the following events will be dispatched to the hidden elements:
- When the action is triggered on the client,
phx:hide-start
is dispatched. - After the time specified by
:time
,phx:hide-end
is dispatched.
Examples
<Text id="item">My Item</Text>
<Button phx-click={LVN.hide(to: "#item")}>
hide!
</Button>
<Button phx-click={LVN.hide(to: "#item", transition: "fade-out-scale")}>
hide fancy!
</Button>
See hide/1
.
Sends a patch event to the server and updates the browser's pushState history.
Options
:replace
- Whether to replace the browser's pushState history. Defaults tofalse
.
Examples
LVN.patch("/my-path")
See patch/1
.
See patch/1
.
Focuses the last pushed element.
Examples
LVN.pop_focus()
Pushes an event to the server.
event
- The string event name to push.
Options
:target
- A selector or component ID to push to. This value will overwrite anyphx-target
attribute present on the element.:loading
- A selector to apply the phx loading classes to.:page_loading
- Boolean to trigger the phx:page-loading-start and phx:page-loading-stop events for this push. Defaults tofalse
.:value
- A map of values to send to the server. These values will be merged over anyphx-value-*
attributes that are present on the element. All keys will be treated as strings when merging.
Examples
<Button phx-click={LVN.push("clicked")}>click me!</Button>
<Button phx-click={LVN.push("clicked", value: %{id: @id})}>click me!</Button>
<Button phx-click={LVN.push("clicked", page_loading: true)}>click me!</Button>
See push/1
.
See push/1
.
Pushes focus from the source element to be later popped.
Options
:to
- An optional ViewTree selector to push focus to. Defaults to the current element.
Examples
LVN.push_focus()
LVN.push_focus(to: "#my-Button")
See push_focus/1
.
Removes an attribute from elements.
attr
- The string attribute name to remove.
Options
:to
- An optional ViewTree selector to remove attributes from. Defaults to the interacted element.
Examples
<Button phx-click={LVN.remove_attribute("aria-expanded", to: "#dropdown")}>
hide
</Button>
See remove_attribute/1
.
See remove_attribute/1
.
Removes classes from elements.
names
- A string with one or more class names to remove.
Options
:to
- An optional ViewTree selector to remove classes from. Defaults to the interacted element.:transition
- A string of classes to apply before removing classes or a 3-tuple containing the transition class, the class to apply to start the transition, and the ending transition class, such as:{"ease-out duration-300", "opacity-0", "opacity-100"}
:time
- The time in milliseconds to apply the transition from:transition
. Defaults to 200.
Examples
<Text id="item">My Item</Text>
<Button phx-click={LVN.remove_class("highlight underline", to: "#item")}>
remove highlight!
</Button>
See remove_class/1
.
See remove_class/1
.
Sets an attribute on elements.
Accepts a tuple containing the string attribute name/value pair.
Options
:to
- An optional ViewTree selector to add attributes to. Defaults to the interacted element.
Examples
<Button phx-click={LVN.set_attribute({"aria-expanded", "true"}, to: "#dropdown")}>
show
</Button>
See set_attribute/1
.
See set_attribute/1
.
Shows elements.
Options
:to
- An optional ViewTree selector to show. Defaults to the interacted element.:transition
- A string of classes to apply before showing or a 3-tuple containing the transition class, the class to apply to start the transition, and the ending transition class, such as:{"ease-out duration-300", "opacity-0", "opacity-100"}
:time
- The time in milliseconds to apply the transition from:transition
. Defaults to 200.:display
- An optional display value to set when showing. Defaults to"block"
.
During the process, the following events will be dispatched to the shown elements:
- When the action is triggered on the client,
phx:show-start
is dispatched. - After the time specified by
:time
,phx:show-end
is dispatched.
Examples
<Text id="item">My Item</Text>
<Button phx-click={LVN.show(to: "#item")}>
show!
</Button>
<Button phx-click={LVN.show(to: "#item", transition: "fade-in-scale")}>
show fancy!
</Button>
See show/1
.
Toggles element visibility.
Options
:to
- An optional ViewTree selector to toggle. Defaults to the interacted element.:in
- A string of classes to apply when toggling in, or a 3-tuple containing the transition class, the class to apply to start the transition, and the ending transition class, such as:{"ease-out duration-300", "opacity-0", "opacity-100"}
:out
- A string of classes to apply when toggling out, or a 3-tuple containing the transition class, the class to apply to start the transition, and the ending transition class, such as:{"ease-out duration-300", "opacity-100", "opacity-0"}
:time
- The time in milliseconds to apply the transition:in
and:out
classes. Defaults to 200.:display
- An optional display value to set when toggling in. Defaults to"block"
.
When the toggle is complete on the client, a phx:show-start
or phx:hide-start
, and
phx:show-end
or phx:hide-end
event will be dispatched to the toggled elements.
Examples
<Text id="item">My Item</Text>
<Button phx-click={LVN.toggle(to: "#item")}>
toggle item!
</Button>
<Button phx-click={LVN.toggle(to: "#item", in: "fade-in-scale", out: "fade-out-scale")}>
toggle fancy!
</Button>
See toggle/1
.
Sets or removes element attribute based on attribute presence.
Accepts a two or three-element tuple:
{attr, val}
- Sets the attribute to the given value or removes it{attr, val1, val2}
- Toggles the attribute betweenval1
andval2
Options
:to
- An optional ViewTree selector to set or remove attributes from. Defaults to the interacted element.
Examples
<Button phx-click={LVN.toggle_attribute({"aria-expanded", "true", "false"}, to: "#dropdown")}>
toggle
</Button>
<Button phx-click={LVN.toggle_attribute({"open", "true"}, to: "#dialog")}>
toggle
</Button>
See toggle_attribute/1
.
See toggle_attribute/1
.
Adds or removes element classes based on presence.
names
- A string with one or more class names to toggle.
Options
:to
- An optional ViewTree selector to target. Defaults to the interacted element.:transition
- A string of classes to apply before adding classes or a 3-tuple containing the transition class, the class to apply to start the transition, and the ending transition class, such as:{"ease-out duration-300", "opacity-0", "opacity-100"}
:time
- The time in milliseconds to apply the transition from:transition
. Defaults to 200.
Examples
<Text id="item">My Item</Text>
<Button phx-click={LVN.toggle_class("active", to: "#item")}>
toggle active!
</Button>
Transitions elements.
transition
- A string of classes to apply before removing classes or a 3-tuple containing the transition class, the class to apply to start the transition, and the ending transition class, such as:{"ease-out duration-300", "opacity-0", "opacity-100"}
Transitions are useful for temporarily adding an animation class to elements, such as for highlighting content changes.
Options
:to
- An optional ViewTree selector to apply transitions to. Defaults to the interacted element.:time
- The time in milliseconds to apply the transition from:transition
. Defaults to 200.
Examples
<Text id="item">My Item</Text>
<Button phx-click={LVN.transition("shake", to: "#item")}>Shake!</Button>
See transition/1
.
See transition/1
.