Zoeken...  ⌘K GitHub

ComparisonTable list

Drie-koloms vergelijking: wij vs. anderen. Vinkje/kruis per feature. Ons kolom geaccentueerd.

/comparison-table
src/components/list/ComparisonTable.astro
---
interface Props {
  eyebrow?: string;
  headline?: string;
  ourLabel?: string;
  theirLabel?: string;
  features: {
    label: string;
    ours: boolean | string;
    theirs: boolean | string;
  }[];
}

const {
  eyebrow,
  headline,
  ourLabel = 'Wij',
  theirLabel = 'Anderen',
  features = [],
} = Astro.props;

const checkSVG = `<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><circle cx="9" cy="9" r="9" fill="rgba(34,197,94,0.12)"/><path d="M5.5 9.5L7.5 11.5L12.5 6.5" stroke="#16a34a" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
const crossSVG = `<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><circle cx="9" cy="9" r="9" fill="rgba(0,0,0,0.06)"/><path d="M6 6L12 12M12 6L6 12" stroke="#9ca3af" stroke-width="1.75" stroke-linecap="round"/></svg>`;

function renderCell(value: boolean | string) {
  if (value === true) return checkSVG;
  if (value === false) return crossSVG;
  return `<span class="cmp__cell-text">${value}</span>`;
}
---

<section class="cmp__section">
  {(eyebrow || headline) && (
    <div class="cmp__header">
      {eyebrow && <p class="cmp__eyebrow">{eyebrow}</p>}
      {headline && <h2 class="cmp__headline">{headline}</h2>}
    </div>
  )}

  <div class="cmp__table-wrap">
    <table class="cmp__table" role="table">
      <thead>
        <tr class="cmp__head-row">
          <th class="cmp__th cmp__th--label" scope="col"></th>
          <th class="cmp__th cmp__th--ours" scope="col">
            <span class="cmp__our-pill">{ourLabel}</span>
          </th>
          <th class="cmp__th cmp__th--theirs" scope="col">
            <span class="cmp__their-label">{theirLabel}</span>
          </th>
        </tr>
      </thead>
      <tbody>
        {features.map((feature, i) => (
          <tr class={`cmp__row${i % 2 === 1 ? ' cmp__row--even' : ''}`}>
            <td class="cmp__td cmp__td--label">{feature.label}</td>
            <td class="cmp__td cmp__td--ours" set:html={renderCell(feature.ours)} />
            <td class="cmp__td cmp__td--theirs" set:html={renderCell(feature.theirs)} />
          </tr>
        ))}
      </tbody>
    </table>
  </div>
</section>

<style>
  :root {
    --color-primary: #0a0a0a;
    --color-accent: #6366f1;
    --color-bg: #fff;
    --color-muted: #6b7280;
    --radius: 0.5rem;
  }

  .cmp__section {
    padding: 5rem 1.5rem;
    max-width: 56rem;
    margin-inline: auto;
  }

  /* Header */
  .cmp__header {
    text-align: center;
    margin-bottom: 2.5rem;
  }

  .cmp__eyebrow {
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--color-accent);
    margin: 0 0 0.75rem;
  }

  .cmp__headline {
    font-size: clamp(1.75rem, 3vw, 2.5rem);
    font-weight: 800;
    color: var(--color-primary);
    margin: 0;
    line-height: 1.15;
  }

  /* Table wrapper */
  .cmp__table-wrap {
    overflow-x: auto;
    border-radius: 0.875rem;
    border: 1px solid rgba(0, 0, 0, 0.09);
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
  }

  /* Table */
  .cmp__table {
    width: 100%;
    border-collapse: collapse;
    table-layout: fixed;
    background: var(--color-bg);
    border-radius: 0.875rem;
    overflow: hidden;
  }

  /* Head */
  .cmp__head-row {
    background: #f9f9fb;
    border-bottom: 1px solid rgba(0, 0, 0, 0.08);
  }

  .cmp__th {
    padding: 1rem 1.25rem;
    text-align: center;
    font-weight: 600;
    font-size: 0.875rem;
    color: var(--color-muted);
  }

  .cmp__th--label {
    text-align: left;
    width: 45%;
  }

  .cmp__th--ours {
    background: var(--color-accent);
    width: 27.5%;
  }

  .cmp__th--theirs {
    width: 27.5%;
  }

  /* Our pill in header */
  .cmp__our-pill {
    display: inline-flex;
    align-items: center;
    padding: 0.25em 0.9em;
    border-radius: 999px;
    background: #fff;
    color: var(--color-accent);
    font-size: 0.8125rem;
    font-weight: 700;
    letter-spacing: 0.03em;
  }

  .cmp__their-label {
    color: var(--color-muted);
  }

  /* Rows */
  .cmp__row {
    border-bottom: 1px solid rgba(0, 0, 0, 0.06);
    transition: background 0.15s ease;
  }

  .cmp__row:last-child {
    border-bottom: none;
  }

  .cmp__row--even {
    background: rgba(0, 0, 0, 0.017);
  }

  .cmp__row:hover {
    background: rgba(99, 102, 241, 0.03);
  }

  /* Cells */
  .cmp__td {
    padding: 0.9rem 1.25rem;
    font-size: 0.9375rem;
    vertical-align: middle;
    text-align: center;
  }

  .cmp__td--label {
    text-align: left;
    color: var(--color-primary);
    font-weight: 500;
  }

  .cmp__td--ours {
    background: rgba(99, 102, 241, 0.04);
  }

  .cmp__td--ours :global(svg),
  .cmp__td--theirs :global(svg) {
    display: inline-block;
    vertical-align: middle;
  }

  .cmp__cell-text {
    font-size: 0.875rem;
    color: var(--color-primary);
    font-weight: 500;
  }

  /* Responsive */
  @media (max-width: 520px) {
    .cmp__td,
    .cmp__th {
      padding: 0.65rem 0.75rem;
      font-size: 0.8125rem;
    }
    .cmp__th--label,
    .cmp__td--label {
      font-size: 0.8125rem;
    }
  }

  @media (prefers-reduced-motion: reduce) {
    * { animation: none !important; transition: none !important; }
  }
</style>

Props

Prop Type Default Beschrijving
features * { label: string; ours: boolean | string; theirs: boolean | string }[] Vergelijkingspunten
ourLabel string 'Wij' Kolom header voor ons
theirLabel string 'Anderen' Kolom header voor anderen
eyebrow string Label boven sectie
headline string Sectie headline

* = verplicht