Pricing

Pricing

Simple pricing that grows with you

Start for free. Upgrade when your team is ready.

Billing period

Starter

For side projects and trying things out.

$0 / month

  • 1 project
  • Community support
  • Basic analytics
Get started

Enterprise

For organizations with advanced needs.

$99 / month

  • Everything in Team
  • SSO and audit logs
  • Dedicated manager
Contact sales

Prices in USD. Cancel anytime.

@use 'sprucecss/scss/spruce' as *;

.pricing-block {
  padding-block: spacer-clamp('xl', 'xxl');

  &__inner {
    display: flex;
    flex-direction: column;
    gap: spacer('l');
  }

  &__toggle {
    display: flex;
    margin-inline: auto;
    max-inline-size: max-content;
  }

  &__note {
    color: color('muted');
    font-size: config('font-size-sm', $typography);
    // A child of the flex __inner: the gap spaces it, so drop the browser margins.
    margin-block: 0;
    text-align: center;
  }
}
<section class="pricing-block" aria-labelledby="pricing-title" data-pricing-block>
    <div class="container">
        <div class="pricing-block__inner">
            <header class="block-heading">
                <p class="block-heading__eyebrow">Pricing</p>
                <h2 class="block-heading__title" id="pricing-title">Simple pricing that grows with you</h2>
                <p class="block-heading__text">Start for free. Upgrade when your team is ready.</p>
            </header>
            <fieldset class="segmented-control pricing-block__toggle">
                <legend class="sr-only">Billing period</legend>
                <label class="segmented-control__option">
                    <input class="segmented-control__input" type="radio" name="pricing-billing" value="monthly" checked>
                    <span>Monthly</span>
                </label>
                <label class="segmented-control__option">
                    <input class="segmented-control__input" type="radio" name="pricing-billing" value="yearly">
                    <span>Yearly <small class="segmented-control__hint">−20%</small></span>
                </label>
            </fieldset>
            <div class="pricing-cards">
                <article class="pricing-card" aria-labelledby="plan-starter">
                    <header class="pricing-card__header">
                        <h3 class="pricing-card__title" id="plan-starter">Starter</h3>
                        <p class="pricing-card__description">For side projects and trying things out.</p>
                    </header>
                    <p class="pricing-card__price"><span class="pricing-card__amount" data-monthly="0" data-yearly="0">$0</span> <span class="pricing-card__period">/ month</span></p>
                    <ul class="pricing-card__features" role="list">
                        <li><svg class="pricing-card__check" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5"/></svg> 1 project</li>
                        <li><svg class="pricing-card__check" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5"/></svg> Community support</li>
                        <li><svg class="pricing-card__check" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5"/></svg> Basic analytics</li>
                    </ul>
                    <a class="btn btn--outline-primary btn--block pricing-card__action" href="#">Get started</a>
                </article>
                <article class="pricing-card pricing-card--featured" aria-labelledby="plan-team">
                    <header class="pricing-card__header">
                        <span class="pricing-card__badge">Most popular</span>
                        <h3 class="pricing-card__title" id="plan-team">Team</h3>
                        <p class="pricing-card__description">For growing teams that ship every week.</p>
                    </header>
                    <p class="pricing-card__price"><span class="pricing-card__amount" data-monthly="29" data-yearly="23">$29</span> <span class="pricing-card__period">/ month</span></p>
                    <ul class="pricing-card__features" role="list">
                        <li><svg class="pricing-card__check" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5"/></svg> Unlimited projects</li>
                        <li><svg class="pricing-card__check" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5"/></svg> Priority support</li>
                        <li><svg class="pricing-card__check" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5"/></svg> Advanced analytics</li>
                        <li><svg class="pricing-card__check" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5"/></svg> Custom domains</li>
                    </ul>
                    <a class="btn btn--primary btn--block pricing-card__action" href="#">Start free trial</a>
                </article>
                <article class="pricing-card" aria-labelledby="plan-enterprise">
                    <header class="pricing-card__header">
                        <h3 class="pricing-card__title" id="plan-enterprise">Enterprise</h3>
                        <p class="pricing-card__description">For organizations with advanced needs.</p>
                    </header>
                    <p class="pricing-card__price"><span class="pricing-card__amount" data-monthly="99" data-yearly="79">$99</span> <span class="pricing-card__period">/ month</span></p>
                    <ul class="pricing-card__features" role="list">
                        <li><svg class="pricing-card__check" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5"/></svg> Everything in Team</li>
                        <li><svg class="pricing-card__check" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5"/></svg> SSO and audit logs</li>
                        <li><svg class="pricing-card__check" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5"/></svg> Dedicated manager</li>
                    </ul>
                    <a class="btn btn--outline-primary btn--block pricing-card__action" href="#">Contact sales</a>
                </article>
            </div>
            <p class="pricing-block__note">Prices in USD. Cancel anytime.</p>
            <p class="sr-only" aria-live="polite" data-pricing-status></p>
        </div>
    </div>
</section>
(() => {
  document.querySelectorAll('[data-pricing-block]').forEach((block) => {
    const status = block.querySelector('[data-pricing-status]');

    block.querySelectorAll('input[name="pricing-billing"]').forEach((input) => {
      input.addEventListener('change', () => {
        const isYearly = input.value === 'yearly';

        block.querySelectorAll('.pricing-card__amount').forEach((amount) => {
          amount.textContent = `$${isYearly ? amount.dataset.yearly : amount.dataset.monthly}`;
          amount.nextElementSibling.textContent = isYearly ? '/ month, billed yearly' : '/ month';
        });

        status.textContent = isYearly ? 'Showing yearly prices.' : 'Showing monthly prices.';
      });
    });
  });
})();

Pricing

On this page

A complete pricing block: the heading, a monthly/yearly toggle and the pricing cards.

Technical Details

  • It combines the Block Heading, the Segmented Control and the Pricing Card components; load their styles too.
  • The toggle is a group of native radio buttons. The script swaps every amount between its data-monthly and data-yearly value, updates the period ("/ month", "/ month, billed yearly") and announces the change in a live region.
  • Without JavaScript, the monthly prices are shown.
  • Set toggle: false in pricingBlock to hide the billing toggle (for one-time prices), and a period per plan in pricingPlans (like "one-time").

Documentation

Learn about Spruce CSS through our extensive documentation.

Components

Explore our UI library of accessible components built with Spruce CSS.

Blocks and Pages

Full-width page blocks and complete page templates, ready to copy.

Find us on GitHub

Did you find a bug? Have an idea or a question? Please open an issue to help us develop the project.