csstailwind-cssphoenix-frameworktailwind-ui

Radial progress bar using TailwindUI


Background

I have a small Phoenix 1.7 app where I am trying to add a radial progress bar, using the default TailwindUI components: https://tailwindui.com/components

Unfortunately for me, I was only able to find normal progress bars:

https://flowbite.com/docs/components/progress/

Namely:

<div class="w-full bg-gray-200 rounded-full h-2.5 dark:bg-gray-700">
  <div class="bg-blue-600 h-2.5 rounded-full" style="width: 45%"></div>
</div>

The only radial progress bar I found was one using DaisyUI:

https://daisyui.com/components/radial-progress/

However, I want to avoid installing anything extra, I really just want to use the default tailwindUI and tailwindCSS that come with Phoenix 1.7

Questions

  1. Does someone know how to create a a radial progress bar component using the default setup that comes with Phoenix LiveView 1.7?
  2. Am I missing some component that already does this?

Solution

  • Answer

    By checking some examples using Tailwind with Apline.js I was able to analyze the code and create a component that does exactly what I want.

    This code uses only Phoniex LiveView vanilla, no extra CSS no extra anything !

    core_components:

      @doc """
      Renders a progress bar for an ongoing operation.
    
      ## Examples
    
          <.progress_bar hidden=false progress=15 />
          <.progress_bar hidden=false progress=20 message="Activating system ..." />
          <.progress_bar hidden=false class="cool-bar" />
      """
      attr :hidden, :boolean, default: true, doc: "whether or not to show the progress bar"
      attr :progress, :integer, default: 0, doc: "the current progress of the bar"
      attr :message, :string, default: "Operation in progress ...", doc: "the message to show while the bar is progressing"
      attr :class, :string, default: nil
    
      def progress_bar(assigns) do
    
        assigns = assign(assigns, :circumference, 2 * 22 / 7 * 120)
        assigns = assign(assigns, :offset, assigns.circumference - assigns.progress / 100 * assigns.circumference)
    
        ~H"""
        <div class={@class} hidden={@hidden}>
          <div class="flex items-center justify-center">
            <p class="text-lg font-semibold"><%= @message %></p>
          </div>
    
          <div class="flex items-center justify-center">
            <svg class="transform -rotate-90 w-72 h-72">
                <circle cx="145" cy="145" r="120" stroke-width="30" fill="transparent" class="stroke-gray-700" />
    
                <circle cx="145" cy="145" r="120" stroke-width="30" fill="transparent"
                    stroke-dasharray={@circumference}
                    stroke-dashoffset={@offset}
                    class="stroke-indigo-500" />
            </svg>
            <span class="absolute text-5xl stroke-black"><%= @progress %></span>
          </div>
    
        </div>
        """
      end
    

    Usage in my_app_live.heex.html:

    <div class="min-h-full max-w-full mx-auto py-6 sm:px-6 lg:px-8">
      <.progress_bar hidden={false} progress={40} message="Activating system ..." />
    </div>
    

    Will produce the following:

    enter image description here

    For more information on how I created this, feel free to check the whole story on the elixir's forum thread:

    https://elixirforum.com/t/radial-progress-bar-using-tailwinui/58098/10?u=fl4m3ph03n1x