UIPackage
Menu

Framework

Change language

Boilerplate repo

Billing Account

blockfinance

Stripe-style account billing page: current-plan card with Pro badge, price and renewal date plus Upgrade / Cancel actions, usage meters for seats and projects, a payment-method row with update and delete actions, and a compact billing-history list with paid badges and per-invoice downloads. Data is hardcoded inline so you can wire it to your own billing API.

Also available for React ->

Installation

$npx shadcn-vue@latest add https://uipkge.dev/r/vue/billing-account.json
Named registry:npx shadcn-vue@latest add @uipkge/billing-accountInstalls to:app/components/blocks/

Variants

Loading interactive previews…

Props

NameType / ValuesDefaultRequired
classHTMLAttributes['class']optional

Schema

Type aliases exported from this item's source. Use these to shape the data you pass in.

UsageMetric
interface UsageMetric {
  label: string
  used: number
  total: number
}
Invoice
interface Invoice {
  id: string
  date: string
  amount: string
  status: 'Paid' | 'Open' | 'Past due'
}

Files installed (1)

  • app/components/blocks/BillingAccount.vue5.4 kB
    <script setup lang="ts">
    import { CreditCard, Download, Trash2 } from 'lucide-vue-next'
    import type { HTMLAttributes } from 'vue'
    import { cn } from '@/lib/utils'
    import { Badge } from '@/components/ui/badge'
    import { Button } from '@/components/ui/button'
    import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
    import { Progress } from '@/components/ui/progress'
    import { Separator } from '@/components/ui/separator'
    
    interface UsageMetric {
      label: string
      used: number
      total: number
    }
    
    interface Invoice {
      id: string
      date: string
      amount: string
      status: 'Paid' | 'Open' | 'Past due'
    }
    
    const plan = {
      name: 'Pro',
      price: '$49',
      cadence: 'month',
      renewalDate: 'September 12, 2026',
    }
    
    const usage: UsageMetric[] = [
      { label: 'Seats', used: 18, total: 20 },
      { label: 'Projects', used: 7, total: 10 },
    ]
    
    const paymentMethod = {
      brand: 'Visa',
      last4: '4242',
      expiry: '04/28',
    }
    
    const invoices: Invoice[] = [
      { id: 'inv-2026-08', date: 'Aug 12, 2026', amount: '$49.00', status: 'Paid' },
      { id: 'inv-2026-07', date: 'Jul 12, 2026', amount: '$49.00', status: 'Paid' },
      { id: 'inv-2026-06', date: 'Jun 12, 2026', amount: '$49.00', status: 'Paid' },
      { id: 'inv-2026-05', date: 'May 12, 2026', amount: '$49.00', status: 'Paid' },
    ]
    
    const props = defineProps<{
      class?: HTMLAttributes['class']
    }>()
    </script>
    
    <template>
      <div data-slot="billing-account" :class="cn('mx-auto w-full max-w-2xl space-y-6', props.class)">
        <Card>
          <CardHeader>
            <div class="flex items-center gap-2">
              <CardTitle>Current plan</CardTitle>
              <Badge>Pro</Badge>
            </div>
            <CardDescription>Your subscription renews automatically each month.</CardDescription>
          </CardHeader>
          <CardContent class="space-y-4">
            <div class="flex flex-wrap items-end justify-between gap-4">
              <div>
                <p class="text-2xl font-bold tracking-tight">
                  {{ plan.price }}
                  <span class="text-muted-foreground text-sm font-normal">/ {{ plan.cadence }}</span>
                </p>
                <p class="text-muted-foreground mt-1 text-xs">Renews on {{ plan.renewalDate }}</p>
              </div>
              <div class="flex items-center gap-2">
                <Button size="sm">Upgrade</Button>
                <Button variant="ghost" size="sm" class="text-destructive hover:text-destructive">
                  Cancel subscription
                </Button>
              </div>
            </div>
          </CardContent>
        </Card>
    
        <Card>
          <CardHeader>
            <CardTitle>Usage</CardTitle>
            <CardDescription>Consumption against your plan limits this cycle.</CardDescription>
          </CardHeader>
          <CardContent class="space-y-5">
            <div v-for="metric in usage" :key="metric.label" class="space-y-2">
              <div class="flex items-center justify-between text-sm">
                <span class="font-medium">{{ metric.label }}</span>
                <span class="text-muted-foreground text-xs tabular-nums">
                  {{ metric.used }} of {{ metric.total }} used
                </span>
              </div>
              <Progress :model-value="(metric.used / metric.total) * 100" />
            </div>
          </CardContent>
        </Card>
    
        <Card>
          <CardHeader>
            <CardTitle>Payment method</CardTitle>
            <CardDescription>Charged when your subscription renews.</CardDescription>
          </CardHeader>
          <CardContent>
            <div class="flex items-center justify-between gap-4">
              <div class="flex items-center gap-3">
                <div
                  class="bg-muted text-muted-foreground border-border flex size-9 shrink-0 items-center justify-center rounded-md border shadow-xs"
                  aria-hidden="true"
                >
                  <CreditCard class="size-4" />
                </div>
                <div>
                  <p class="text-sm font-medium tabular-nums">•••• •••• •••• {{ paymentMethod.last4 }}</p>
                  <p class="text-muted-foreground text-xs">
                    {{ paymentMethod.brand }} · Expires {{ paymentMethod.expiry }}
                  </p>
                </div>
              </div>
              <div class="flex items-center gap-1">
                <Button variant="ghost" size="sm">Update</Button>
                <Button variant="ghost" size="icon-sm" aria-label="Delete payment method">
                  <Trash2 class="text-muted-foreground size-4" />
                </Button>
              </div>
            </div>
          </CardContent>
        </Card>
    
        <Card>
          <CardHeader>
            <CardTitle>Billing history</CardTitle>
            <CardDescription>Invoices from the last 12 months.</CardDescription>
          </CardHeader>
          <CardContent>
            <ul class="-my-2 divide-y">
              <li v-for="invoice in invoices" :key="invoice.id" class="flex items-center justify-between gap-4 py-3">
                <div class="min-w-0">
                  <p class="text-sm font-medium">{{ invoice.date }}</p>
                  <p class="text-muted-foreground text-xs tabular-nums">{{ invoice.amount }}</p>
                </div>
                <div class="flex items-center gap-2">
                  <Badge variant="success">{{ invoice.status }}</Badge>
                  <Separator orientation="vertical" class="!h-4" />
                  <Button variant="ghost" size="icon-sm" aria-label="Download invoice">
                    <Download class="text-muted-foreground size-4" />
                  </Button>
                </div>
              </li>
            </ul>
          </CardContent>
        </Card>
      </div>
    </template>
    

Raw manifest:https://uipkge.dev/r/vue/billing-account.json