Senren UI
Components / Progress

Progress

Stable

task progress

Migration 68%
Provisioning 92%
Quota 84%

Usage example #

Copy this ERB into a Rails view after installing the component. The snippet below is the same code used by the live preview above.

app/views/.../progress_example.html.erb
<div class="w-full max-w-md space-y-4">
  <%= render Senren::ProgressComponent.new(label: "Migration", value: 68, variant: :default) %>
  <%= render Senren::ProgressComponent.new(label: "Provisioning", value: 92, variant: :success) %>
  <%= render Senren::ProgressComponent.new(label: "Quota", value: 84, variant: :warning) %>
</div>

Install this component #

Copy the official component into your app

Use this when you want the Senren-maintained implementation copied into app/components/senren.

Terminal
bin/rails senren:add progress

Create a custom component with the same conventions

Use this when you need an app-specific static component that follows Senren's ViewComponent structure.

Terminal
bin/rails generate senren:component progress --no-client

At a glance #

Category Data
Class name Senren::ProgressComponent
Stimulus
Variants default, success, warning, destructive
Depends on
Pairs with card, alert

Source #

app/components/senren/progress_component.html.erb
<div <%= tag.attributes(**root_attrs("w-full")) %>>
  <% if label.present? %>
    <div class="mb-2 flex items-center justify-between text-sm">
      <span class="font-medium text-[hsl(var(--senren-foreground))]"><%= label %></span>
      <span class="text-[hsl(var(--senren-muted-foreground))]"><%= percent %>%</span>
    </div>
  <% end %>
  <div role="progressbar" aria-valuemin="0" aria-valuemax="<%= max.to_i %>" aria-valuenow="<%= value.to_i %>" class="h-2.5 w-full overflow-hidden rounded-full bg-[hsl(var(--senren-muted))]">
    <div class="h-full rounded-full transition-[width] duration-300 ease-out <%= indicator_class %>" style="width: <%= percent %>%"></div>
  </div>
</div>
app/components/senren/progress_component.rb
# frozen_string_literal: true

module Senren
  class ProgressComponent < BaseComponent
    VARIANTS = {
      default: '',
      success: '',
      warning: '',
      destructive: ''
    }.freeze
    INDICATOR_VARIANTS = {
      default: 'bg-[hsl(var(--senren-primary))]',
      success: 'bg-[hsl(var(--senren-success))]',
      warning: 'bg-[hsl(var(--senren-warning))]',
      destructive: 'bg-[hsl(var(--senren-destructive))]'
    }.freeze
    SIZES = { md: '' }.freeze

    def initialize(value: 0, max: 100, label: nil, variant: :default, class_name: nil, **html)
      super(variant: variant, size: :md, class_name: class_name, **html)
      @value = value.to_f
      @max = max.to_f.positive? ? max.to_f : 100.0
      @label = label
    end

    attr_reader :value, :max, :label

    def percent
      ((value / max) * 100).clamp(0, 100).round
    end

    def indicator_class
      INDICATOR_VARIANTS.fetch(variant)
    end
  end
end

AI agent rules #

Use for

  • +task progress
  • +file upload
  • +loading bars

Avoid

  • -decorative animation

Accessibility #

  • role=progressbar with aria-valuenow/min/max.