How To Build a [Counter with Elixir, Phoenix, LiveView and Tailwind CSS] | No Javascript
Tags: elixir, programming, functional, tutorial
Published: 2022-02-15 02:36:00

## 
&nbsp;
&nbsp;

{% youtube sGvjH3H-Yfc  %}

&nbsp;
&nbsp;


Learn how to use Elixir/Phoenix, to create a counter without javascript, only using Elixir with the help of Phoenix LiveView, and Tailwind CSS for the user interface.

### Step 1:

Let's create a fresh elixir/phoenix new project by going to the command line and typing the following in your desired directory:

`$ mix phx.new counter --no-ecto --no-gettext --no-mailer --no-dashboard && cd counter`

### Step 2:

Let's add and configure Tailwind CSS, go to the website https://hex.pm and search for the tailwind library to grab the latest version, so you can copy and that to your mix config file, at the time of the making of this tutorial the latest version is 0.1.5, add the following to your project dependencies inside your `mix.exs` file:

`{:tailwind, "~> 0.1.5"}`

Then in the command line type in `$ mix deps.get && mix tailwind.install` to fetch your new dependency and install tailwind. Back in your `mix.exs` file, under aliases, add the following:

`"assets.deploy": ["tailwind default --minify", ..., "phx.digest"]`

Go to your `config/config/exs` file and add the following configuration:

```elixir
config :tailwind,
  version: "3.0.10",
  default: [
    args: ~w(
      --config=tailwind.config.js
      --input=css/app.css
      --output=../priv/static/assets/app.css
    ),
    cd: Path.expand("../assets", __DIR__)
  ]
```

Go to your `config/dev.exs` file and add the following to your `watchers`:

```elixir
tailwind: {Tailwind, :install_and_run, [:default, ~w(--watch)]}
```

### Step 3:

Add the following folder under `test/counter_web`:

`live`

Add the following file to that newly created folder:

`page_live_test.exs`

To that newly created file `test/counter_web/live/page_live_test.exs` add the following tests:

```elixir
defmodule CounterWeb.PageLiveTest do
  use CounterWeb.ConnCase

  import Phoenix.LiveViewTest

  test "disconnected and connected render", %{conn: conn} do
    {:ok, page_live, disconnected_html} = live(conn, "/")
    assert disconnected_html =~ "0"
    assert render(page_live) =~ "0"
  end

  test "increment event and decrement", %{conn: conn} do
    {:ok, page_live, _html} = live(conn, "/")
    assert render_click(page_live, :inc, %{}) =~ "1"
    assert render_click(page_live, :inc, %{}) =~ "2"
    assert render_click(page_live, :inc, %{}) =~ "3"
    assert render_click(page_live, :dec, %{}) =~ "2"
    assert render_click(page_live, :dec, %{}) =~ "1"
    assert render_click(page_live, :dec, %{}) =~ "0"
  end

  test "clear event", %{conn: conn} do
    {:ok, page_live, _html} = live(conn, "/")
    assert render_click(page_live, :inc, %{}) =~ "1"
    assert render_click(page_live, :clear, %{}) =~ "0"
  end
end
```

If you run those tests by going to the command line and typing `mix test test/counter_web/live` they should fail of course.

### Step 4:

Open your `lib/counter_web/router.ex` file and remove the root path and change it to the following:

```elixir
  scope "/", CounterWeb do
    pipe_through :browser

    live "/", PageLive
  end
```

Run the server with the following command in your terminal:

`$ iex -S mix phx.server`

Open your `lib/counter_web/templates/layout/root.html.heex` and remove the header nav, your html body tag should look like the following:

```html
  <body>
    <%= @inner_content %>
  </body>
```

To your `lib/counter_web/templates/layout/live.html.heex` file, add the following css class to your main tag:

```html
<main class="container mx-auto max-w-full">
```

Add the following folder to `lib/counter_web`:

`live`

Add the following file to that newly created `live` folder:

`page_live.ex`

Add the following to that newly created file `lib/counter_web/live/page_live.ex`:

```elixir
defmodule CounterWeb.PageLive do
  use CounterWeb, :live_view
end
```

Under `lib/counter_web/live` add the following file:

`page_live.html.heex`

Add the following to that newly created `lib/counter_web/live/page_live_html.heex` file:

```html
<div class="flex flex-col items-center justify-center h-screen bg-gray-200">
  <h1 class="text-5xl font-medium text-gray-700">Counter</h1>

  <span class="m-5 text-9xl">
    0
  </span>
  
  <section> 
    <button class="text-white text-4xl bg-indigo-600 px-6 py-4 rounded hover:bg-indigo-900">-</button>

    <button class="m-10 text-white text-4xl bg-indigo-900 px-6 py-4 rounded hover:bg-indigo-500">clear</button>

    <button class="text-white text-4xl bg-indigo-600 px-6 py-4 rounded hover:bg-indigo-900">+</button>
  </section>
</div>
```

### Step 5:

Let's add our liveview mount function and assign the default number.

To `lib/counter_web/live/page_live.ex` file add the following function:

```elixir
  def mount(_params, _session, socket) do
    {:ok,
     socket
     |> assign(number: 0)}
  end
```

Then change the number 0 to our new assign variable in our `lib/counter_web/live/page_lve.html.heex` file, inside our span tag:

```elixir
  <span class="m-5 text-9xl">
    <%= @number %>
  </span>
``` 

### Step 6:

Inside our `lib/counter_web/live/page_lve.html.heex` file, add the following click event binding to our increase button:

```html
<button phx-click="inc" class="...">+</button>
```

Then to our `lib/counter_web/live/page_live.ex` file let's add the following function to handle that event:

```elixir
  def handle_event("inc", _params, socket) do
    {:noreply,
     socket
     |> update(:number, &(&1 + 1))}
  end
```

### Step 7:

Inside our `lib/counter_web/live/page_lve.html.heex` file, add the following click event binding to our decrease button:

```html
<button phx-click="dec" class="...">-</button>
```

To our `lib/counter_web/live/page_live.ex` file let's add the following function to handle the decrease event:

```elixir
  def handle_event("dec", _params, socket) do
    {:noreply,
     socket
     |> update(:number, &max(0, &1 - 1))}
  end
```

### Step 8:

Let's add the following click event binding to our clear button inside our `lib/counter_web/live/page_lve.html.heex` file:

 ```html
<button phx-click="clear" class="...">clear</button>
```

To our `lib/counter_web/live/page_live.ex` file let's add the following function to handle the clear event:

```elixir
  def handle_event("clear", _params, socket) do
    {:noreply, socket |> assign(number: 0)}
  end
```

Go to http://localhost:4000 to test your application manually as a user, and if you go to the command line and run the tests with `mix test test/counter_web/live` they should pass with no failure.

## Conclusion

That's all folks, we went through the simple steps to set up Tailwind CSS with your phoenix applications, and how to handle click events with Phoenix LiveView over sockets without the need of using Javascript code, the Javascript is handled nicely in the background for us by the LiveView library. Thank you so much for your time, I really appreciate it.


&nbsp;
&nbsp;


[![Join The Elixir Army](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cv2q172ztuekdtw82vo9.png)](https://elixirprogrammer.com)