Shapes — Dynamic Styles with Phoenix Live View

Exploring (simple) ways to generate dynamic styling for your Phoenix Live View projects

The Setup

For this article, I created a demo project called Playground. I intend to use it for some future articles as well. The live demo is also deployed to Heroku. The context dedicated to the present article is called Shapes. Our demo will use some squares that should change the color, size, and location in a dynamic way.

1. Dynamic CSS Classes

The first example goal is to change the shape’s color on the user's radio-button selection.

.green {
background-color: green;
}
.blue {
background-color: blue;
}
.red {
background-color: red;
}
}
<div class={"shape", @shape_color}>
<div class={class_one: my_function(@assign_one), class_two: @boolean_assign, ... etc.}>

When to use it

  • you know all the object states and they can be translated into multiple CSS classes
  • as often as possible. It will keep your templates clean and readable

2. JS Hooks

This example addresses custom user input. The user drags a slider that adjusts the shape size.

<div class="playground" id="resize_playground" :hook="DynamicStyle">
<div class="shape" id="resize_shape">
</div>
</div>
def handle_event("change_size", %{"style" => %{"size" => size}}, socket) do
size = String.to_integer(size)
socket = push_event(socket, "change_size", %{size: size})
{:noreply, assign(socket, :shape_size, size)}
end
let DynamicStyle = {
mounted() {
this.handleEvent('change_size', ({ size }) => {
const shape = document.getElementById('resize_shape');
shape.style.height = px(size);
shape.style.width = px(size);
});
},
};
const px = (val) => `${val}px`;export { DynamicStyle };

When to use it

  • the object state cannot be predefined
  • you prefer using JS rather than Elixir to update the DOM
  • you want to apply complex styles or transitions
  • you want to use external JS libraries for even more complex transformations, physics, or animations. Eg. matter.js

3. Elixir-only

The third and last example uses Elixir code to update the styles. There are two sliders this time. They correspond to the X and Y axes of the container. Dragging them changes the shape's position inside the parent element.

<div class="shape" style={@style}>
data style, :list, default: [left: "0px", top: "0px"]def handle_event("change_position", %{"style" => %{"x_axis" => x, "y_axis" => y}}, socket) do
style = [left: x <> "px", top: y <> "px"]
{:noreply, assign(socket, style: style)}
end

When to use it

  • you need to deal with basic but highly dynamic style changes
  • you have a personal preference of writing Elixir over JS

Conclusion

We covered the basics of three potential approaches to add dynamic styles to the Live View templates. Worth mentioning, the 3 models are not mutually exclusive. You can combine them however you see it fit.

elixir dev | dorian.iacobescu@gmail.com | @iac0bs0n