# Pricing Section v6

> Three full-width plan cards with an inverted Basic plan, above a striped comparison table that shares the card columns so every value sits under its plan, all wrapped in one outer card.

A shadcn/ui block from the [@uiception](https://uiception.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/uiception/pricing-section-v6).

- Page, with a live preview: https://shadcn.exchange/r/uiception/pricing-section-v6
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/uiception/pricing-section-v6-light-eabb9835504aaa56.png
- Registry item: https://uiception.com/r/pricing-section-v6.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://uiception.com/r/pricing-section-v6.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `lucide-react`
- Registry items: `button`

## Files

### `registry/new-york/blocks/pricing-section-v6/page.tsx`

```tsx
import PricingSectionV6 from "./components/pricing-section-v6"

export default function Page() {
  return <PricingSectionV6 />
}
```

### `registry/new-york/blocks/pricing-section-v6/components/pricing-section-v6.tsx`

```tsx
import PricingCard from "./pricing-card"
import PricingTable from "./pricing-table"
import { pricingPlans } from "../lib/pricing-plans"

export default function PricingSectionV6() {
  return (
    <section className="py-4 md:py-6 lg:py-8">
      <div className="mx-auto max-w-6xl px-4 sm:px-6 lg:px-8">
        <div className="mx-auto mb-10 max-w-2xl text-center">
          <h2 className="text-4xl font-medium tracking-tight text-balance text-foreground md:text-5xl">
            Our plans scale with{" "}
            <span className="text-muted-foreground">your business</span>
          </h2>
        </div>
        <div className="flex flex-col gap-6 rounded-3xl border border-border bg-card p-3 sm:p-4 md:gap-8 md:p-5">
          {/* Stacks on mobile; from md it matches `planGridClassName` so cards sit over their table values. */}
          <div className="flex flex-col gap-3 md:grid md:grid-cols-3 md:gap-x-4">
            {pricingPlans.map((plan) => (
              <PricingCard key={plan.id} plan={plan} />
            ))}
          </div>
          <PricingTable />
        </div>
      </div>
    </section>
  )
}
```

### `registry/new-york/blocks/pricing-section-v6/components/pricing-card.tsx`

```tsx
import { Button } from "@/components/ui/button"
import { cn } from "@/lib/utils"
import type { PricingPlan } from "../lib/pricing-plans"

type PricingCardProps = {
  plan: PricingPlan
}

export default function PricingCard({ plan }: PricingCardProps) {
  const inverted = plan.highlighted ?? false

  return (
    <div
      className={cn(
        "flex min-w-0 flex-col items-center rounded-2xl px-6 pt-8 pb-6 text-center",
        inverted ? "bg-foreground" : "bg-muted"
      )}
    >
      <h3
        className={cn(
          "text-lg font-medium tracking-tight",
          inverted ? "text-background" : "text-foreground"
        )}
      >
        {plan.name}
      </h3>
      <p
        className={cn(
          "mt-4 text-4xl font-semibold tracking-tight md:text-5xl",
          inverted ? "text-background" : "text-foreground"
        )}
      >
        {plan.price}
      </p>
      <p
        className={cn(
          "mt-2 text-sm",
          inverted ? "text-background/65" : "text-muted-foreground"
        )}
      >
        {plan.priceSuffix}
      </p>
      <Button
        size="lg"
        className={cn(
          "mt-6 w-full max-w-48 rounded-full",
          inverted && "bg-background text-foreground hover:bg-background/90"
        )}
      >
        {plan.ctaLabel}
      </Button>
    </div>
  )
}
```

### `registry/new-york/blocks/pricing-section-v6/components/pricing-table.tsx`

```tsx
import { cn } from "@/lib/utils"
import { featureLabelClassName, planGridClassName } from "../lib/layout"
import { pricingFeatures, pricingPlans } from "../lib/pricing-plans"
import FeatureValue from "./feature-value"

export default function PricingTable() {
  return (
    <div role="table" aria-label="Plan comparison" className="flex flex-col">
      <div role="rowgroup">
        {/* Plan names: visible when cards stack on mobile, screen-reader only once they sit above their columns. */}
        <div role="row" className={cn(planGridClassName, "pb-3 md:sr-only")}>
          <span role="columnheader" className="sr-only">
            Feature
          </span>
          {pricingPlans.map((plan) => (
            <span
              key={plan.id}
              role="columnheader"
              className="text-center text-sm font-medium text-foreground"
            >
              {plan.name}
            </span>
          ))}
        </div>
      </div>
      <div role="rowgroup" className="flex flex-col">
        {pricingFeatures.map((feature, index) => (
          <div
            key={feature.label}
            role="row"
            className={cn(
              planGridClassName,
              "relative min-h-10 items-center gap-y-1.5 rounded-lg py-2",
              index % 2 === 0 && "bg-muted"
            )}
          >
            <span
              role="rowheader"
              className={cn(
                "col-span-3 pl-3 text-xs text-foreground sm:pl-5 sm:text-sm",
                featureLabelClassName
              )}
            >
              {feature.label}
            </span>
            {pricingPlans.map((plan) => (
              <span
                key={plan.id}
                role="cell"
                className="flex items-center justify-center"
              >
                <FeatureValue value={feature.values[plan.id]} />
              </span>
            ))}
          </div>
        ))}
      </div>
    </div>
  )
}
```

### `registry/new-york/blocks/pricing-section-v6/components/feature-value.tsx`

```tsx
import { CheckIcon, XIcon } from "lucide-react"

import type { FeatureValue as FeatureValueType } from "../lib/pricing-plans"

type FeatureValueProps = {
  value: FeatureValueType
}

export default function FeatureValue({ value }: FeatureValueProps) {
  if (typeof value === "string") {
    return (
      <span className="text-xs font-medium text-foreground sm:text-sm">
        {value}
      </span>
    )
  }

  if (value) {
    return (
      <span className="inline-flex size-4 items-center justify-center rounded-full border border-emerald-600/50 text-emerald-600 dark:border-emerald-400/50 dark:text-emerald-400">
        <CheckIcon aria-hidden className="size-2.5" strokeWidth={3} />
        <span className="sr-only">Included</span>
      </span>
    )
  }

  return (
    <span className="inline-flex size-4 items-center justify-center rounded-full border border-red-500/50 text-red-500 dark:border-red-400/50 dark:text-red-400">
      <XIcon aria-hidden className="size-2.5" strokeWidth={3} />
      <span className="sr-only">Not included</span>
    </span>
  )
}
```

### `registry/new-york/blocks/pricing-section-v6/lib/pricing-plans.ts`

```ts
export type PlanId = "free" | "basic" | "pro"

export type PricingPlan = {
  id: PlanId
  name: string
  price: string
  priceSuffix: string
  ctaLabel: string
  /** Rendered as the dark, inverted card. */
  highlighted?: boolean
}

/** `true` renders a check, `false` a muted cross, a string renders as-is. */
export type FeatureValue = boolean | string

export type PricingFeature = {
  label: string
  values: Record<PlanId, FeatureValue>
}

export const pricingPlans: PricingPlan[] = [
  {
    id: "free",
    name: "Free",
    price: "$0",
    priceSuffix: "Per month",
    ctaLabel: "Get Started",
  },
  {
    id: "basic",
    name: "Basic",
    price: "$25",
    priceSuffix: "Per month",
    ctaLabel: "Get Started",
    highlighted: true,
  },
  {
    id: "pro",
    name: "Pro",
    price: "$50",
    priceSuffix: "Per month",
    ctaLabel: "Get Started",
  },
]

export const pricingFeatures: PricingFeature[] = [
  {
    label: "Team members",
    values: { free: "1", basic: "2", pro: "3" },
  },
  {
    label: "Projects",
    values: { free: "3", basic: "10", pro: "20" },
  },
  {
    label: "Published apps",
    values: { free: false, basic: "2", pro: "5" },
  },
  {
    label: "Integrations",
    values: { free: true, basic: true, pro: true },
  },
  {
    label: "Custom domains",
    values: { free: false, basic: true, pro: true },
  },
  {
    label: "Enabled workflows",
    values: { free: false, basic: "1", pro: "Unlimited" },
  },
  {
    label: "Priority support",
    values: { free: false, basic: false, pro: true },
  },
]
```

### `registry/new-york/blocks/pricing-section-v6/lib/layout.ts`

```ts
/**
 * One grid for the plan cards and every comparison row: one column per plan.
 * Sharing it is what keeps each value centered under its card.
 */
export const planGridClassName = "grid grid-cols-3 gap-x-2 sm:gap-x-4"

/**
 * From md the feature label floats inside the first plan column, capped at the
 * space left of that column's centered value: (row − 2 gaps) / 6 is half a
 * column, minus 1rem so it never touches the value.
 */
export const featureLabelClassName =
  "md:absolute md:inset-y-0 md:left-0 md:flex md:w-[calc((100%-2rem)/6-1rem)] md:items-center"
```
