Vue componentFree

Pricing Single

Single-plan Vue 3 pricing card with a feature checklist, a sale price, a money-back guarantee and one clear CTA. Tailwind CSS, dark mode, typed props.

by Vueplayv1.0.0Updated 3 hours ago

Install
Full screen ↗

About this component

When you sell one thing, a three-column pricing table just adds noise. This card puts the plan name, a two-column checklist of what is included and a focused price panel side by side, with the guarantee right under the button where hesitation happens.

It suits courses, templates, lifetime deals, desktop apps and flat-rate SaaS. Set compareAtPrice to show a struck-through launch discount (announced properly to screen readers), change period to "/ month" for a subscription, and use the default slot to add a testimonial or FAQ link under the feature list.

On mobile the price panel stacks under the features so the call to action is the last thing people see before they scroll on.

  • Two-column feature checklist
  • Optional struck-through compare price
  • Money-back guarantee line
  • Stacks cleanly on mobile
  • Light and dark mode

Code

11 files in the repo
<script setup lang="ts">
withDefaults(defineProps<{
  heading?: string
  subheading?: string
  planName?: string
  planDescription?: string
  /** Price in whole currency units. */
  price?: number
  /** Optional original price, shown struck through. null hides it. */
  compareAtPrice?: number | null
  currency?: string
  /** Text after the price, e.g. "one-time" or "/ month". */
  period?: string
  features?: string[]
  ctaLabel?: string
  /** Guarantee line under the button. Empty string hides it. */
  guarantee?: string
  /** Small note under the guarantee, e.g. taxes or payment methods. */
  note?: string
}>(), {
  heading: 'One price. Everything included.',
  subheading: 'No tiers, no seat math, no upsells. Buy Fretboard Pro once and keep every update for the life of the product.',
  planName: 'Lifetime licence',
  planDescription: 'The full course library, practice tools and every future lesson, for as long as you play.',
  price: 149,
  compareAtPrice: 229,
  currency: '$',
  period: 'one-time',
  features: () => [
    '180+ video lessons from beginner to advanced',
    'Interactive fretboard and chord trainer',
    'Downloadable tabs and backing tracks',
    'Progress tracking across all your devices',
    'Monthly live Q&A sessions',
    'All future courses at no extra cost',
  ],
  ctaLabel: 'Get lifetime access',
  guarantee: '30-day money-back guarantee. If it is not for you, email us and we refund you in full.',
  note: 'Prices in USD. Taxes calculated at checkout.',
})

const emit = defineEmits<{
  select: []
}>()
</script>

<template>
  <section class="px-6 py-20 sm:py-24 lg:px-8">
    <div class="mx-auto max-w-2xl text-center">
      <h2 class="text-3xl font-bold tracking-tight text-balance text-gray-900 sm:text-4xl dark:text-white">{{ heading }}</h2>
      <p class="mt-4 text-lg text-pretty text-gray-600 dark:text-gray-400">{{ subheading }}</p>
    </div>

    <article class="mx-auto mt-14 grid max-w-4xl overflow-hidden rounded-3xl bg-white shadow-xl ring-1 shadow-gray-900/5 ring-gray-200 lg:grid-cols-[1fr_20rem] dark:bg-gray-900 dark:shadow-black/30 dark:ring-gray-800">
      <div class="p-8 sm:p-10">
        <h3 class="text-2xl font-bold tracking-tight text-gray-900 dark:text-white">{{ planName }}</h3>
        <p class="mt-3 text-base text-gray-600 dark:text-gray-400">{{ planDescription }}</p>
        <div class="mt-8 flex items-center gap-4">
          <h4 class="shrink-0 text-sm font-semibold text-rose-600 dark:text-rose-400">What is included</h4>
          <div class="h-px flex-1 bg-gray-100 dark:bg-gray-800" />
        </div>
        <ul class="mt-6 grid gap-4 text-sm text-gray-700 sm:grid-cols-2 sm:gap-x-6 dark:text-gray-300">
          <li v-for="feature in features" :key="feature" class="flex gap-3">
            <svg viewBox="0 0 20 20" aria-hidden="true" class="size-5 shrink-0 fill-rose-600 dark:fill-rose-400"><path fill-rule="evenodd" d="M16.7 5.3a1 1 0 0 1 0 1.4l-8 8a1 1 0 0 1-1.4 0l-4-4a1 1 0 1 1 1.4-1.4L8 12.6l7.3-7.3a1 1 0 0 1 1.4 0Z" clip-rule="evenodd" /></svg>
            {{ feature }}
          </li>
        </ul>
        <slot />
      </div>

      <div class="m-2 flex flex-col justify-center rounded-2xl bg-gray-50 px-8 py-10 text-center ring-1 ring-gray-900/5 ring-inset dark:bg-gray-950/60 dark:ring-white/5">
        <p class="text-sm font-semibold text-gray-600 dark:text-gray-400">Pay once, own it forever</p>
        <p class="mt-5 flex items-baseline justify-center gap-x-2">
          <span v-if="compareAtPrice && compareAtPrice > price" class="text-lg font-medium text-gray-400 line-through dark:text-gray-500">
            <span class="sr-only">Was</span>{{ currency }}{{ compareAtPrice }}
          </span>
          <span class="text-5xl font-bold tracking-tight text-gray-900 dark:text-white">
            <span v-if="compareAtPrice && compareAtPrice > price" class="sr-only">now</span>{{ currency }}{{ price }}
          </span>
          <span v-if="period" class="text-sm font-medium text-gray-600 dark:text-gray-400">{{ period }}</span>
        </p>
        <button
          type="button"
          class="mt-8 w-full rounded-xl bg-rose-600 px-4 py-3 text-sm font-semibold text-white shadow-sm transition hover:bg-rose-500 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-rose-600 dark:bg-rose-500 dark:hover:bg-rose-400"
          @click="emit('select')"
        >
          {{ ctaLabel }}
        </button>
        <p v-if="guarantee" class="mt-5 flex items-start gap-2 text-left text-xs leading-5 text-gray-600 dark:text-gray-400">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="mt-0.5 size-4 shrink-0 text-rose-600 dark:text-rose-400"><path d="M12 3 5 6v5c0 4.5 3 8.3 7 10 4-1.7 7-5.5 7-10V6l-7-3Z" /><path d="m9 12 2 2 4-4" /></svg>
          {{ guarantee }}
        </p>
        <p v-if="note" class="mt-3 text-xs text-gray-500 dark:text-gray-500">{{ note }}</p>
      </div>
    </article>
  </section>
</template>

Props

PropTypeDefaultDescription
headingstring'One price. Everything included.'Section heading.
subheadingstring'No tiers, no seat math, no upsells…'Supporting text under the heading.
planNamestring'Lifetime licence'Plan title inside the card.
planDescriptionstring'The full course library, practice tools…'One-line plan summary.
pricenumber149Price in whole currency units.
compareAtPricenumber | null229Original price shown struck through when higher than price. Pass null to hide.
currencystring'$'Currency symbol before prices.
periodstring'one-time'Text after the price, e.g. '/ month'.
featuresstring[]6 course featuresChecklist items.
ctaLabelstring'Get lifetime access'Button text.
guaranteestring'30-day money-back guarantee…'Guarantee line with a shield icon. Empty string hides it.
notestring'Prices in USD. Taxes calculated at checkout.'Small print at the bottom of the price panel.

Events

EventPayloadDescription
select()Fired when the CTA button is clicked.

Slots

SlotDescription
defaultExtra content under the feature list, e.g. a testimonial.
All pricing tables →
Preview of Pricing ComparisonFree

Component · Pricing tables

Pricing Comparison

Vue 3 plan comparison table with grouped feature rows, check and dash cells, a sticky plan header on desktop and stacked cards on mobile. Tailwind CSS.

by Vueplay
Preview of Pricing TiersFree

Component · Pricing tables

Pricing Tiers

Three-tier Vue 3 pricing table with a monthly/yearly toggle, a highlighted plan and a select event. Tailwind CSS, dark mode, fully typed props.

by Vueplay
Preview of Hero SplitFree

Component · Hero sections

Hero Split

Split Vue 3 hero section with copy and two CTAs on the left and a Tailwind-drawn app window mockup on the right. Dark mode, typed props, no images.

by Vueplay1 installs
Preview of Bento GridFree

Component · Feature sections

Bento Grid

Bento-style Vue 3 feature grid with wide and tall tiles and small CSS-drawn visuals like maps, timelines and code. Tailwind CSS, dark mode, typed tiles.

by Vueplay

Pro feature

Upgrade to Pro

Upgrade to unlock more of Vueplay. Cancel any time.

  • Custom domains with HTTPS
  • Private projects
  • No "Made with Vueplay" badge
  • GitHub sync

$120/year

Compare plansBilling settings