Pricing

Pricing with a billing toggle

A monthly / yearly switch above the plans. The prices are computed from one number each, so the copy cannot drift.

6 components62 linesClient componentSource on GitHub

Live demo

Full width · the frame has its own viewport, so the breakpoints are real

What it uses

Imports

import { Button, Container, Pricing, Stack, Switch, Text } from '@the_viveksingh/vivek-ui'

The block

This is the file that renders the demo above, read at build time. Copy it into your project, change the words, and it runs — the only thing it needs is @the_viveksingh/vivek-ui and its stylesheet.

'use client'

import { Button, Container, Pricing, Stack, Switch, Text } from '@the_viveksingh/vivek-ui'
import { useState } from 'react'

const BASE = [
  {
    id: 'starter',
    name: 'Starter',
    monthly: 12,
    description: 'For solo makers.',
    features: ['1 seat', '5 GB storage', 'Email support'],
  },
  {
    id: 'team',
    name: 'Team',
    monthly: 39,
    description: 'For small teams.',
    features: ['10 seats', '100 GB storage', 'Shared workspaces', 'Priority support'],
    highlighted: true,
    badge: 'Best value',
  },
  {
    id: 'business',
    name: 'Business',
    monthly: 99,
    description: 'For whole companies.',
    features: ['Unlimited seats', '1 TB storage', 'SSO and audit log', 'Dedicated manager'],
  },
]

export default function PricingWithToggle() {
  const [yearly, setYearly] = useState(false)
  const plans = BASE.map((plan) => ({
    ...plan,
    price: `$${yearly ? Math.round(plan.monthly * 0.8) : plan.monthly}`,
    period: yearly ? '/month, billed yearly' : '/month',
    cta: (
      <Button fullWidth variant={plan.highlighted ? 'solid' : 'outline'}>
        Choose {plan.name}
      </Button>
    ),
  }))

  return (
    <>
      <Container size="md" style={{ paddingBlockStart: '3rem' }}>
        <Stack align="center" gap={2}>
          <Switch
            label={yearly ? 'Billed yearly — saving 20%' : 'Bill yearly and save 20%'}
            checked={yearly}
            onChange={(event) => setYearly(event.target.checked)}
          />
          <Text size="sm" tone="muted">
            Switch any time. Yearly plans are refundable for 30 days.
          </Text>
        </Stack>
      </Container>
      <Pricing padding="md" title="Pick a plan" plans={plans} />
    </>
  )
}