Skip to content

PricingCard

SM · 950B gzip budget

Pricing tier display with features list and CTA button.

Category
Media & layout
Budget
sm, single-purpose control
External runtime
React / React DOM only
axe fixtureSSR rendersource scanbundle budget

Preview

Live fixture
Preview locale

Pro

$9/mo
  • Feature 1
  • Feature 2

Try the component here. Locale-aware formatting and direction follow the selected language; example content and labels are not automatically translated. Overlay demos use interactive launchers.

Install

npx shadcn@latest add https://gear5-ui.vercel.app/r/pricing-card.json

Copies the source into your project.

New here? Set up Tailwind and import aliases first →

Source & props

Edit on GitHub ↗

Prop types and inline documentation are included below. This is repository source; the installer rewrites shared imports for your project.

"use client";

import React from "react";

export interface PricingCardProps {
  planName: string;
  price: string;
  period?: string;
  description?: string;
  features: string[];
  ctaText?: string;
  onCtaClick?: () => void;
  highlighted?: boolean;
  className?: string;
  ariaLabel?: string;
}

export function PricingCard({
  planName,
  price,
  period,
  description,
  features,
  ctaText = "Get started",
  onCtaClick,
  highlighted = false,
  className = "",
  ariaLabel,
}: PricingCardProps) {
  return (
    <article
      aria-label={ariaLabel ?? `${planName} pricing plan`}
      className={className}
      style={{
        border: highlighted
          ? "2px solid var(--color-primary, #3b82f6)"
          : "1px solid var(--color-border, #e5e7eb)",
        borderRadius: "0.75rem",
        padding: "2rem",
        background: "var(--color-bg, #fff)",
        display: "flex",
        flexDirection: "column",
        position: "relative",
        overflow: "hidden",
      }}
    >
      {highlighted && (
        <div
          aria-hidden="true"
          style={{
            position: "absolute",
            top: 0,
            insetInline: 0,
            height: "3px",
            background: "var(--color-primary, #3b82f6)",
          }}
        />
      )}

      <h3
        style={{
          fontSize: "1.25rem",
          fontWeight: 600,
          marginBlockEnd: "0.5rem",
        }}
      >
        {planName}
      </h3>

      <div style={{ marginBlockEnd: "0.5rem" }}>
        <span style={{ fontSize: "2.5rem", fontWeight: 700 }}>{price}</span>
        {period && (
          <span
            style={{
              fontSize: "0.875rem",
              color: "var(--color-muted, #6b7280)",
              marginInlineStart: "0.25rem",
            }}
          >
            / {period}
          </span>
        )}
      </div>

      {description && (
        <p
          style={{
            fontSize: "0.875rem",
            color: "var(--color-muted, #6b7280)",
            marginBlockEnd: "1.5rem",
            lineHeight: 1.5,
          }}
        >
          {description}
        </p>
      )}

      <ul
        role="list"
        style={{
          listStyle: "none",
          padding: 0,
          margin: 0,
          marginBlockEnd: "1.5rem",
          flex: 1,
          display: "flex",
          flexDirection: "column",
          gap: "0.75rem",
        }}
      >
        {features.map((feature, index) => (
          <li
            key={index}
            style={{
              display: "flex",
              alignItems: "flex-start",
              gap: "0.5rem",
              fontSize: "0.875rem",
            }}
          >
            <span aria-hidden="true" style={{ color: "var(--color-success, #10b981)", flexShrink: 0 }}>✓</span>
            {feature}
          </li>
        ))}
      </ul>

      <button
        type="button"
        onClick={onCtaClick}
        aria-label={`${ctaText} for ${planName}`}
        style={{
          width: "100%",
          padding: "0.75rem 1.5rem",
          borderRadius: "0.5rem",
          border: highlighted ? "none" : "1px solid var(--color-border, #e5e7eb)",
          background: highlighted
            ? "var(--color-primary, #3b82f6)"
            : "var(--color-bg, #fff)",
          color: highlighted ? "#fff" : "var(--color-text, #111827)",
          fontWeight: 600,
          fontSize: "0.875rem",
          cursor: "pointer",
          transition: "background 0.2s, color 0.2s",
        }}
      >
        {ctaText}
      </button>
    </article>
  );
}

What CI checks

Quality contract
  • Bundled, minified and gzipped against its tier budget
  • Audited by axe in the state previewed above
  • Rendered through react-dom/server with no browser globals
  • Scanned for network calls, dangerous sinks, and unguarded animation