Senren UI
Components / Billing Plan Card

Billing Plan Card

Stable

pricing page or billing settings

Popular

Pro

For focused teams shipping client work.

$24 per seat / month
  • +Unlimited projects
  • +Team audit trail
  • +Priority support
Upgrade

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/.../billing_plan_card_example.html.erb
<div class="w-full max-w-sm">
  <%= render Senren::BillingPlanCardComponent.new(
    name: "Pro",
    price: "$24",
    interval: "per seat / month",
    description: "For focused teams shipping client work.",
    features: ["Unlimited projects", "Team audit trail", "Priority support"],
    cta_label: "Upgrade",
    badge: "Popular",
    variant: :recommended
  ) %>
</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 billing_plan_card

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 billing_plan_card --no-client

Dependencies are resolved by senren:add: card, button, badge, typography.

At a glance #

Category Saas
Class name Senren::BillingPlanCardComponent
Stimulus
Variants default, current, recommended
Depends on card, button, badge, typography
Pairs with settings_section

Source #

app/components/senren/billing_plan_card_component.html.erb
<%= tag.div(**root_attrs("relative rounded-(--senren-radius) border bg-[hsl(var(--senren-card))] p-6 shadow-sm")) do %>
  <% if badge.present? %>
    <span class="absolute right-4 top-4 rounded-full bg-[hsl(var(--senren-accent))] px-2.5 py-1 text-xs font-semibold text-[hsl(var(--senren-accent-foreground))]"><%= badge %></span>
  <% end %>

  <% if content? && name.blank? %>
    <%= content %>
  <% else %>
    <% if name.present? %><h3 class="font-display text-lg font-semibold text-[hsl(var(--senren-foreground))]"><%= name %></h3><% end %>
    <% if description.present? %><p class="mt-2 text-sm leading-6 text-[hsl(var(--senren-muted-foreground))]"><%= description %></p><% end %>
    <% if price.present? %>
      <div class="mt-5 flex items-end gap-1">
        <span class="font-display text-4xl font-semibold tracking-tight text-[hsl(var(--senren-foreground))]"><%= price %></span>
        <% if interval.present? %><span class="pb-1 text-sm text-[hsl(var(--senren-muted-foreground))]"><%= interval %></span><% end %>
      </div>
    <% end %>
    <% if features.any? %>
      <ul class="mt-5 space-y-2 text-sm text-[hsl(var(--senren-muted-foreground))]">
        <% features.each do |feature| %>
          <li class="flex gap-2"><span class="text-[hsl(var(--senren-success))]">+</span><span><%= feature %></span></li>
        <% end %>
      </ul>
    <% end %>
    <% if cta_label.present? %>
      <%= link_to cta_label, cta_href || "#", class: "mt-6 inline-flex h-10 w-full items-center justify-center rounded-(--senren-radius) bg-[hsl(var(--senren-primary))] px-4 text-sm font-medium text-[hsl(var(--senren-primary-foreground))] hover:opacity-90" %>
    <% end %>
  <% end %>
<% end %>
app/components/senren/billing_plan_card_component.rb
# frozen_string_literal: true

module Senren
  class BillingPlanCardComponent < BaseComponent
    VARIANTS = {
      default: 'border-[hsl(var(--senren-border))]',
      current: 'border-[hsl(var(--senren-accent))]',
      recommended: 'border-[hsl(var(--senren-primary))]'
    }.freeze
    SIZES = { md: '' }.freeze

    def initialize(name: nil, price: nil, interval: nil, description: nil, features: [], cta_label: nil, cta_href: nil,
                   badge: nil, variant: :default, class_name: nil, **html)
      super(variant: variant, size: :md, class_name: class_name, **html)
      @name = name
      @price = price
      @interval = interval
      @description = description
      @features = Array(features)
      @cta_label = cta_label
      @cta_href = cta_href
      @badge = badge
    end

    attr_reader :name, :price, :interval, :description, :features, :cta_label, :cta_href, :badge
  end
end

AI agent rules #

Use for

  • +pricing page or billing settings

Avoid

  • -feature comparison tables - use table

Accessibility #

  • Use heading; price and features must be readable.