Billing Plan Card
Stablepricing page or billing settings
Popular
Pro
For focused teams shipping client work.
$24
per seat / month
- +Unlimited projects
- +Team audit trail
- +Priority support
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.