UIPackage
Menu

Framework

Change language

Boilerplate repo

Pricing Tier Comparison Matrix

blockmarketing

Comprehensive pricing tier comparison matrix with billing cycle discount toggles, prominent recommended plan, and granular capability matrix table.

Also available for React ->

Installation

$npx shadcn-vue@latest add https://uipkge.dev/r/vue/pricing-tier-comparison-matrix.json
Named registry:npx shadcn-vue@latest add @uipkge/pricing-tier-comparison-matrixInstalls to:app/components/blocks/

Variants

Loading interactive previews…

Schema

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

Plan
interface Plan {
  id: string
  name: string
  description: string
  monthlyPrice: number
  annualPrice: number
  highlight: boolean
  badge?: string
  ctaText: string
  ctaVariant: 'default' | 'outline' | 'secondary'
}
FeatureComparisonRow
interface FeatureComparisonRow {
  category: string
  features: {
    name: string
    tooltip: string
    community: boolean | string
    pro: boolean | string
    enterprise: boolean | string
  }[]
}

npm dependencies

Files installed (1)

  • app/components/blocks/PricingTierComparisonMatrix.vue11.3 kB
    <script setup lang="ts">
    import { ref } from 'vue'
    import { ArrowRight, Check, Minus, ShieldCheck } from 'lucide-vue-next'
    import { Badge } from '@/components/ui/badge'
    import { Button } from '@/components/ui/button'
    import { Card } from '@/components/ui/card'
    
    type BillingCycle = 'monthly' | 'annual'
    
    const billing = ref<BillingCycle>('annual')
    
    interface Plan {
      id: string
      name: string
      description: string
      monthlyPrice: number
      annualPrice: number
      highlight: boolean
      badge?: string
      ctaText: string
      ctaVariant: 'default' | 'outline' | 'secondary'
    }
    
    const plans: Plan[] = [
      {
        id: 'community',
        name: 'Community OSS',
        description: 'For indie hackers and developers building open source products.',
        monthlyPrice: 0,
        annualPrice: 0,
        highlight: false,
        ctaText: 'Start Building Free',
        ctaVariant: 'outline',
      },
      {
        id: 'pro',
        name: 'Pro Team',
        description: 'For growing startup engineering teams that require high velocity.',
        monthlyPrice: 29,
        annualPrice: 24,
        highlight: true,
        badge: 'Most Popular',
        ctaText: 'Claim Pro License',
        ctaVariant: 'default',
      },
      {
        id: 'enterprise',
        name: 'Enterprise Scale',
        description: 'Dedicated registry syncing, SSO, SOC2 compliance audits, and SLA.',
        monthlyPrice: 119,
        annualPrice: 99,
        highlight: false,
        ctaText: 'Talk to Sales',
        ctaVariant: 'outline',
      },
    ]
    
    interface FeatureComparisonRow {
      category: string
      features: {
        name: string
        tooltip: string
        community: boolean | string
        pro: boolean | string
        enterprise: boolean | string
      }[]
    }
    
    const comparisonData: FeatureComparisonRow[] = [
      {
        category: 'Registry & Core Primitives',
        features: [
          {
            name: 'Full AST Component Source Access',
            tooltip: 'Raw SFC and TSX source files copied directly into your repository.',
            community: true,
            pro: true,
            enterprise: true,
          },
          {
            name: 'Dual-Framework Parity (Vue + React)',
            tooltip: 'Identical DOM semantics and CVA tokens across both ecosystems.',
            community: true,
            pro: true,
            enterprise: true,
          },
          {
            name: 'Curated Marketing & SaaS Blocks',
            tooltip: 'Access to 450+ production-grade unbundled layout blocks.',
            community: '100+ Blocks',
            pro: 'All 450+ Blocks',
            enterprise: 'All Blocks + Custom',
          },
          {
            name: 'Tailwind CSS v4 OKLCH Token System',
            tooltip: 'Hardware-calibrated color spaces and spring curves.',
            community: true,
            pro: true,
            enterprise: true,
          },
        ],
      },
      {
        category: 'Enterprise & Security Compliance',
        features: [
          {
            name: 'Private Registry Mirroring',
            tooltip: 'Host your organization’s customized internal registry behind a firewall.',
            community: false,
            pro: '1 Private Repo',
            enterprise: 'Unlimited Private Hubs',
          },
          {
            name: 'SOC2 & ISO 27001 Audit Packs',
            tooltip: 'Pre-certified security documentation and architecture proofs.',
            community: false,
            pro: false,
            enterprise: true,
          },
          {
            name: 'Guaranteed 99.99% Registry CDN SLA',
            tooltip: 'Global multi-region edge distribution uptime guarantee.',
            community: false,
            pro: '99.9% SLA',
            enterprise: '99.99% High Availability',
          },
          {
            name: 'Dedicated Design Engineering Support',
            tooltip: 'Direct Slack / Discord channel with core design system maintainers.',
            community: false,
            pro: 'Priority Email',
            enterprise: 'Dedicated Slack Channel',
          },
        ],
      },
    ]
    </script>
    
    <template>
      <section
        data-slot="pricing-tier-comparison-matrix"
        class="bg-background relative overflow-hidden px-4 py-16 sm:px-6 sm:py-24 lg:px-8"
      >
        <div class="mx-auto max-w-7xl space-y-16">
          <!-- Header -->
          <div class="mx-auto max-w-3xl space-y-4 text-center">
            <Badge variant="secondary" class="gap-1.5 px-3 py-1 font-mono text-xs shadow-xs">
              <ShieldCheck class="text-primary size-3.5" />
              Predictable Pricing
            </Badge>
            <h2 class="text-foreground text-3xl font-bold tracking-tight sm:text-4xl">
              Zero seat taxes. Own your source code forever.
            </h2>
            <p class="text-muted-foreground text-base">
              Choose the tier that fits your engineering team's delivery scale and compliance needs.
            </p>
    
            <!-- Billing Toggle -->
            <div class="flex items-center justify-center gap-3 pt-4">
              <span
                class="font-mono text-xs"
                :class="billing === 'monthly' ? 'text-foreground font-bold' : 'text-muted-foreground'"
              >
                Monthly
              </span>
              <div class="border-border bg-card relative flex items-center rounded-full border p-1">
                <button
                  type="button"
                  class="relative z-10 rounded-full px-3 py-1 font-mono text-xs transition-colors"
                  :class="
                    billing === 'monthly'
                      ? 'bg-primary text-primary-foreground font-semibold shadow-xs'
                      : 'text-muted-foreground'
                  "
                  @click="billing = 'monthly'"
                >
                  Monthly
                </button>
                <button
                  type="button"
                  class="relative z-10 flex items-center gap-1.5 rounded-full px-3 py-1 font-mono text-xs transition-colors"
                  :class="
                    billing === 'annual'
                      ? 'bg-primary text-primary-foreground font-semibold shadow-xs'
                      : 'text-muted-foreground'
                  "
                  @click="billing = 'annual'"
                >
                  <span>Annual</span>
                  <span class="bg-success rounded-full px-1.5 py-0.5 text-xs font-bold text-white">Save 20%</span>
                </button>
              </div>
            </div>
          </div>
    
          <!-- Pricing Plan Cards Grid (3 Columns) -->
          <div class="grid grid-cols-1 items-stretch gap-6 md:grid-cols-3">
            <Card
              v-for="plan in plans"
              :key="plan.id"
              class="border-border bg-card relative flex flex-col justify-between space-y-6 rounded-2xl p-6 text-left shadow-xl transition-colors sm:p-8"
              :class="
                plan.highlight
                  ? 'border-primary/80 ring-primary/20 scale-[1.02] shadow-sm ring-2'
                  : 'hover:border-border/80'
              "
            >
              <!-- Top Badge -->
              <div v-if="plan.badge" class="absolute -top-3 left-1/2 -translate-x-1/2">
                <Badge class="px-3 py-0.5 font-mono text-xs tracking-wider uppercase shadow-md">
                  {{ plan.badge }}
                </Badge>
              </div>
    
              <div class="space-y-4">
                <div>
                  <h3 class="text-foreground font-mono text-xl font-bold">{{ plan.name }}</h3>
                  <p class="text-muted-foreground mt-1 min-h-[36px] text-xs">{{ plan.description }}</p>
                </div>
    
                <!-- Price display -->
                <div class="flex items-baseline gap-1.5 font-mono">
                  <span class="text-foreground text-4xl font-bold">
                    ${{ billing === 'annual' ? plan.annualPrice : plan.monthlyPrice }}
                  </span>
                  <span class="text-muted-foreground text-xs">/ month</span>
                </div>
                <p class="text-muted-foreground font-mono text-xs">
                  {{
                    billing === 'annual' && plan.annualPrice > 0
                      ? 'Billed annually ($' + plan.annualPrice * 12 + '/yr)'
                      : 'Billed monthly'
                  }}
                </p>
              </div>
    
              <Button :variant="plan.ctaVariant" class="h-10 w-full gap-1.5 font-mono text-xs shadow-xs">
                <span>{{ plan.ctaText }}</span>
                <ArrowRight class="size-3.5" />
              </Button>
            </Card>
          </div>
    
          <!-- Deep Feature Comparison Matrix Table -->
          <div class="space-y-6">
            <div class="text-center">
              <h3 class="text-foreground font-mono text-xl font-bold">Detailed Feature Comparison</h3>
              <p class="text-muted-foreground mt-1 text-xs">Full granular matrix of capabilities and entitlements.</p>
            </div>
    
            <Card class="border-border bg-card overflow-hidden rounded-2xl text-left shadow-sm">
              <div class="overflow-x-auto">
                <table class="w-full border-collapse text-left text-xs">
                  <thead>
                    <tr class="border-border bg-muted/40 text-muted-foreground border-b font-mono">
                      <th class="w-1/2 p-4 font-semibold">Capability</th>
                      <th class="p-4 text-center font-semibold">Community</th>
                      <th class="text-primary p-4 text-center font-bold font-semibold">Pro Team</th>
                      <th class="p-4 text-center font-semibold">Enterprise</th>
                    </tr>
                  </thead>
                  <tbody>
                    <template v-for="(section, sIdx) in comparisonData" :key="sIdx">
                      <tr class="bg-muted/20 border-border/80 border-b">
                        <td
                          colspan="4"
                          class="text-muted-foreground p-3 px-4 font-mono text-xs font-bold tracking-wider uppercase"
                        >
                          {{ section.category }}
                        </td>
                      </tr>
                      <tr
                        v-for="(row, rIdx) in section.features"
                        :key="rIdx"
                        class="border-border/60 hover:bg-muted/10 border-b transition-colors"
                      >
                        <td class="p-4">
                          <div class="text-foreground font-medium">{{ row.name }}</div>
                          <div class="text-muted-foreground mt-0.5 text-xs">{{ row.tooltip }}</div>
                        </td>
                        <td class="p-4 text-center font-mono">
                          <template v-if="typeof row.community === 'boolean'">
                            <Check v-if="row.community" class="text-success mx-auto size-4" />
                            <Minus v-else class="text-muted-foreground/40 mx-auto size-4" />
                          </template>
                          <span v-else class="text-muted-foreground">{{ row.community }}</span>
                        </td>
                        <td class="p-4 text-center font-mono font-semibold">
                          <template v-if="typeof row.pro === 'boolean'">
                            <Check v-if="row.pro" class="text-success mx-auto size-4" />
                            <Minus v-else class="text-muted-foreground/40 mx-auto size-4" />
                          </template>
                          <span v-else class="text-primary">{{ row.pro }}</span>
                        </td>
                        <td class="p-4 text-center font-mono">
                          <template v-if="typeof row.enterprise === 'boolean'">
                            <Check v-if="row.enterprise" class="text-success mx-auto size-4" />
                            <Minus v-else class="text-muted-foreground/40 mx-auto size-4" />
                          </template>
                          <span v-else class="text-foreground font-semibold">{{ row.enterprise }}</span>
                        </td>
                      </tr>
                    </template>
                  </tbody>
                </table>
              </div>
            </Card>
          </div>
        </div>
      </section>
    </template>
    

Raw manifest:https://uipkge.dev/r/vue/pricing-tier-comparison-matrix.json