# Large table 02

> A heading over a plan comparison table with plan icons and the middle plan highlighted.

URL: https://apogee.avaui.dev/docs/pricing-sections/large-table-02
Last updated: 2026-10-20

A heading over a plan comparison table with plan icons and the middle plan highlighted.

Last updated October 20, 2026

Live example: https://apogee.avaui.dev/examples/pricing/large-table-02

```astro
---
/**
 * Large table 02: A heading over a plan comparison table with plan icons and the middle plan highlighted.
 *
 * @block pricing
 * @order 22
 */
import { CircleCheck, CircleHelp, Layers2, Layers3, Minus, Zap } from '@lucide/astro'
import Section from '@/components/apogee/Section/Section.astro'
import SectionHeader from '@/components/apogee/SectionHeader/SectionHeader.astro'
import Button from '@/components/apogee/Button/Button.astro'
import FeaturedIcon from '@/components/apogee/FeaturedIcon/FeaturedIcon.astro'
import Table from '@/components/apogee/Table/Table.astro'
import Tooltip from '@/components/apogee/Tooltip/Tooltip.astro'
import { plain } from '@/components/apogee/sections/_shared/spine.ts'
import type { PricingContent } from '@/components/apogee/sections/_shared/pricing.ts'

/** @composable */
interface Props extends PricingContent {
  /** 1 when the block opens a page. */
  headingLevel?: 1 | 2
  /** Feature groups; each row's `values` follow `items` in order: `true` included, `false` not, text as written. The first group's name is for screen readers only. @shape { name, rows: { name, tip?, values: (string | boolean)[] }[] } @category content */
  comparison?: { name: string; rows: { name: string; tip?: string; values: (string | boolean)[] }[] }[]
}

const {
  headingLevel = 2,
  eyebrow = 'Pricing',
  heading = 'Simple, transparent pricing',
  description = 'We believe good tools should be open to every company, whatever its size.',
  items = [
    { name: 'Basic plan', price: '$10', period: 'month', description: 'Our most popular plan.', features: [], action: { label: 'Get started', href: '#' } },
    { name: 'Business plan', price: '$20', period: 'month', description: 'Best for growing teams.', features: [], action: { label: 'Get started', href: '#' }, featured: true },
    { name: 'Enterprise plan', price: '$40', period: 'month', description: 'Best for large teams.', features: [], action: { label: 'Get started', href: '#' } },
  ],
  comparison = [
    { name: 'Overview', rows: [
      { name: 'Basic features', tip: 'Core tools you need to manage your workspace and get started.', values: [true, true, true] },
      { name: 'Users', tip: 'Add, remove and manage people, with control over their access.', values: ['10', '20', 'Unlimited'] },
      { name: 'Individual data', tip: 'Data and activity for each person in your workspace.', values: ['20 GB', '40 GB', 'Unlimited'] },
      { name: 'Support', tip: 'Help centre, email and in-app help during business hours.', values: [true, true, true] },
      { name: 'Automated workflows', tip: 'Automate repeated tasks to save time and effort.', values: [false, true, true] },
      { name: '200+ integrations', tip: 'Connect the tools you already use.', values: [false, true, true] },
    ] },
    { name: 'Reporting and analytics', rows: [
      { name: 'Analytics', tip: 'Trends, usage and key numbers across your account.', values: ['Basic', 'Advanced', 'Advanced'] },
      { name: 'Export reports', tip: 'Download reports as CSV or PDF.', values: [true, true, true] },
      { name: 'Scheduled reports', tip: 'Reports built and emailed on a schedule.', values: [true, true, true] },
      { name: 'API access', tip: 'Work with your data, users and workflows from code.', values: [false, true, true] },
      { name: 'Advanced reports', tip: 'Custom charts, filters and drill-downs.', values: [false, true, true] },
      { name: 'Saved reports', tip: 'Save report settings you use often.', values: [false, true, true] },
      { name: 'Customer properties', tip: 'Your own data points for each customer.', values: [false, false, true] },
      { name: 'Custom fields', tip: 'Add fields to users, reports or properties.', values: [false, false, true] },
    ] },
    { name: 'User access', rows: [
      { name: 'SSO and SAML sign-in', tip: 'Single sign-on with your identity provider.', values: [true, true, true] },
      { name: 'Advanced permissions', tip: 'Choose who can view, edit or manage each area.', values: [false, true, true] },
      { name: 'Audit log', tip: 'A history of actions and changes across your organisation.', values: [false, false, true] },
      { name: 'Data history', tip: 'See changes and trends over time.', values: [false, false, true] },
    ] },
  ],
} = Astro.props
const PlanHeading = headingLevel === 1 ? 'h2' : 'h3'
const icons = [Zap, Layers2, Layers3]
// A featured plan's column is tinted down the whole wide table.
const tint = (i: number) => (items[i]?.featured ? ' bg-primary-faded/40' : '')
---

<Section spacing="large">
  <div class="flex flex-col gap-12 md:gap-16">
    <SectionHeader headingLevel={headingLevel} eyebrow={eyebrow ?? undefined} heading={plain(heading)} description={description ?? undefined} size="large" />
    <div class="max-lg:hidden">
      <Table size="medium" striped class="table-fixed">
        <thead>
          <tr>
            <td class="w-1/4"></td>
            {items.map((plan, i) => {
              const Icon = icons[i % icons.length]!
              return (
            <th scope="col" class={`w-1/4 align-top${tint(i)}`}>
            <div class="flex flex-col gap-4 py-2 text-start font-normal">
              <FeaturedIcon theme="outline" color="neutral" size="medium"><Icon /></FeaturedIcon><p class="flex items-center gap-2 text-xl font-semibold">{plan.name}</p>
              <p class="flex items-baseline gap-1"><span class="text-5xl font-semibold tracking-tight tabular-nums">{plan.price}</span>{plan.period && <span class="text-neutral-faded">per {plan.period}</span>}</p>
              <p class="text-sm text-neutral-faded">{plan.description}</p>
              <Button href={plan.action.href} fullWidth>{plan.action.label}</Button>
            </div>
          </th>
              )
            })}
          </tr>
        </thead>
        <tbody>
          {comparison.map((group, gi) => (
            <>
          <tr><th scope="colgroup" colspan={items.length + 1} class={gi === 0 ? 'sr-only' : 'pt-8 text-sm font-semibold text-primary'}>{group.name}</th></tr>
          {group.rows.map((row) => (
          <tr><th scope="row" class="font-medium"><span class="inline-flex items-center gap-1.5">{row.name}{row.tip && <Tooltip text={row.tip}><button type="button" class="rounded-full text-neutral-faded hover:text-neutral focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus" aria-label={`About ${row.name.toLowerCase()}`}><CircleHelp class="size-4" aria-hidden="true" /></button></Tooltip>}</span></th>{row.values.map((v, i) => <td class={`text-center${tint(i)}`}>{v === true ? <CircleCheck class="mx-auto size-5 text-positive" aria-label="Included" /> : v === false ? <Minus class="mx-auto size-5 text-neutral-faded" aria-label="Not included" /> : v}</td>)}</tr>
          ))}
            </>
          ))}
        </tbody>
      </Table>
    </div>
    <div class="flex flex-col gap-16 lg:hidden">
      {items.map((plan, pi) => (
      <div class="flex flex-col gap-6">
        <div class="flex flex-col gap-3">
          <PlanHeading class="flex items-center gap-2 text-xl font-semibold">{plan.name}</PlanHeading>
          <p class="flex items-baseline gap-1"><span class="text-5xl font-semibold tracking-tight tabular-nums">{plan.price}</span>{plan.period && <span class="text-neutral-faded">per {plan.period}</span>}</p>
          <p class="text-sm text-neutral-faded">{plan.description}</p>
          <Button href={plan.action.href} fullWidth>{plan.action.label}</Button>
        </div>
        {comparison.map((group, gi) => (
        <Table size="small" striped><caption class={gi === 0 ? 'sr-only' : 'pb-2 text-start text-sm font-semibold text-primary'}>{group.name}</caption><tbody>{group.rows.map((row) => { const v = row.values[pi]; return <tr><th scope="row" class="font-medium">{row.name}</th><td class="text-end">{v === true ? <CircleCheck class="ms-auto size-5 text-positive" aria-label="Included" /> : v === false ? <Minus class="ms-auto size-5 text-neutral-faded" aria-label="Not included" /> : v}</td></tr> })}</tbody></Table>
        ))}
      </div>
      ))}
    </div>
  </div>
</Section>
```

## Add

```sh
npx @ava-ui/apogee add pricing/large-table-02
```

This copies the block to `src/components/apogee/blocks/pricing/` with everything it uses: Button, FeaturedIcon, Section, SectionHeader, Table, Tooltip. Every piece of copy is a prop, with the sample copy as its default. Pass yours, or `null` to hide a part; see [copy is props](https://apogee.avaui.dev/docs/pricing-sections#copy-is-props).

## Accessibility

-   The heading is an `h2` by default, so the block slots into a page under its `h1`; item titles are one level down.

## Related

[

PricingPlan tiers side by side, with an optional monthly / annual switch.

](https://apogee.avaui.dev/docs/sections/pricing)[

SegmentedControlA row of connected, mutually exclusive options backed by native radios — pick one from a small, always-visible set.

](https://apogee.avaui.dev/docs/segmented-control)[

TableA styled, horizontally-scrollable table. Write plain thead/tbody markup — Table only styles it.

](https://apogee.avaui.dev/docs/table)
