Zoeken...  ⌘K GitHub

IconComparison icon

Vergelijkingstabel met feature-rijen en twee kolommen, ideaal voor bureau vs. concurrent positionering.

/icon-comparison
src/components/icon/IconComparison.astro
---
interface ComparisonRow {
  feature: string;
  colA: string | boolean;
  colB: string | boolean;
}

interface Props {
  title?: string;
  labelA?: string;
  labelB?: string;
  rows?: ComparisonRow[];
}

const {
  title,
  labelA = 'Optie A',
  labelB = 'Optie B',
  rows = [],
} = Astro.props;

function renderVal(val: string | boolean) {
  if (val === true) return { type: 'yes', text: '✓' };
  if (val === false) return { type: 'no', text: '✗' };
  return { type: 'text', text: String(val) };
}
---

<section class:list={['bl-section', 'icmpr-section']}>
  <div class="bl-inner">
    {title && <h2 class="icmpr__title">{title}</h2>}
    <div class="icmpr__table">
      <div class="icmpr__header">
        <div class="icmpr__h-feature"></div>
        <div class="icmpr__h-col icmpr__h-col--a">{labelA}</div>
        <div class="icmpr__h-col icmpr__h-col--b">{labelB}</div>
      </div>
      {rows.map(row => {
        const a = renderVal(row.colA);
        const b = renderVal(row.colB);
        return (
          <div class="icmpr__row">
            <div class="icmpr__feature">{row.feature}</div>
            <div class="icmpr__val icmpr__val--a">
              {a.type !== 'text'
                ? <span class:list={['icmpr__bool', `icmpr__bool--${a.type}`]}>{a.text}</span>
                : a.text}
            </div>
            <div class="icmpr__val icmpr__val--b">
              {b.type !== 'text'
                ? <span class:list={['icmpr__bool', `icmpr__bool--${b.type}`]}>{b.text}</span>
                : b.text}
            </div>
          </div>
        );
      })}
    </div>
  </div>
</section>

<style>
  .icmpr-section { background: var(--color-bg, #fff); }
  .icmpr__title {
    font-size: 2rem;
    font-weight: 700;
    color: var(--color-primary, #0a0a0a);
    text-align: center;
    margin: 0 0 2rem;
  }
  .icmpr__table { border: 1px solid #eee; border-radius: 12px; overflow: hidden; }
  .icmpr__header, .icmpr__row {
    display: grid;
    grid-template-columns: 2fr 1fr 1fr;
  }
  .icmpr__header { background: #f9f9f9; border-bottom: 2px solid #eee; }
  .icmpr__h-feature, .icmpr__h-col {
    padding: .9rem 1.25rem;
    font-size: .85rem;
    font-weight: 700;
    color: #555;
  }
  .icmpr__h-col--b { color: var(--color-accent, #6366f1); background: #6366f10a; }
  .icmpr__row { border-bottom: 1px solid #f0f0f0; }
  .icmpr__row:last-child { border-bottom: none; }
  .icmpr__row:hover { background: #fafafa; }
  .icmpr__feature {
    padding: .85rem 1.25rem;
    font-size: .9rem;
    color: var(--color-primary, #0a0a0a);
    font-weight: 500;
    display: flex;
    align-items: center;
  }
  .icmpr__val {
    padding: .85rem 1.25rem;
    display: flex;
    align-items: center;
    font-size: .9rem;
    color: #555;
  }
  .icmpr__val--b { background: #6366f108; }
  .icmpr__bool { font-size: 1rem; font-weight: 700; }
  .icmpr__bool--yes { color: #16a34a; }
  .icmpr__bool--no { color: #dc2626; }
</style>

Props

Prop Type Default Beschrijving
title string - Tabelkop
labelA string 'Optie A' Kolomlabel links
labelB string 'Optie B' Kolomlabel rechts (geaccentueerd)
rows * { feature: string; colA: string | boolean; colB: string | boolean }[] - Tabelrijen; boolean wordt vink/kruis

* = verplicht