Zoeken...  ⌘K GitHub

IconTabs icon

CSS-only tabs: een rij labels met icoon, elk gekoppeld aan een tekstpaneel. Werkt zonder JS.

/icon-tabs
src/components/icon/IconTabs.astro
---
/**
 * IconTabs
 * CSS-only tab-blok: een rij labels met icoon, elk gekoppeld aan een
 * tekstpaneel. Werkt zonder JS via radio-inputs. Prop-driven.
 *
 * Props:
 * - tabs: { icon?: string; label: string; body: string }[]
 */
interface Tab {
  icon?: string;
  label: string;
  body: string;
}
interface Props {
  tabs?: Tab[];
}
const { tabs = [] } = Astro.props;
// WHY: radio-name moet uniek zijn per instance, anders delen meerdere
// IconTabs-blokken op één pagina dezelfde checked-state.
const uid = 'itabs-' + Math.random().toString(36).slice(2, 8);
---

<section class="bl-section itabs">
  <div class="bl-inner bl-inner--narrow itabs-inner">
    <div class="itabs-wrap">
      {tabs.map((_, i) => (
        <input class="itabs-radio" type="radio" name={uid} id={`${uid}-${i}`} checked={i === 0} />
      ))}
      <div class="itabs-bar" role="tablist">
        {tabs.map((t, i) => (
          <label class="itabs-label" for={`${uid}-${i}`}>
            {t.icon && <span class="itabs-icon" aria-hidden="true">{t.icon}</span>}
            <span class="itabs-text">{t.label}</span>
          </label>
        ))}
      </div>
      <div class="itabs-panels">
        {tabs.map((t, i) => (
          <div class={`itabs-panel itabs-panel--${i}`}><p>{t.body}</p></div>
        ))}
      </div>
    </div>
  </div>
</section>

<style>
.itabs-wrap{--color-accent: #6366f1;--color-primary: #0a0a0a}
.itabs-radio{position:absolute;opacity:0;pointer-events:none}
.itabs-bar{display:flex;border-bottom:2px solid #e5e7eb;gap:0;flex-wrap:wrap}
.itabs-label{display:flex;align-items:center;gap:8px;padding:12px 20px;cursor:pointer;font-size:1rem;font-weight:600;color:#52525b;border-bottom:2px solid transparent;margin-bottom:-2px;transition:color .15s;white-space:nowrap}
.itabs-label:hover{color:var(--color-primary)}
.itabs-icon{font-size:1rem}
.itabs-panels{padding:24px 0}
.itabs-panel{display:none;font-size:1rem;line-height:1.7;color:#374151}
.itabs-panel p{margin:0}
.itabs-radio:nth-of-type(1):checked ~ .itabs-bar label:nth-of-type(1),
.itabs-radio:nth-of-type(2):checked ~ .itabs-bar label:nth-of-type(2),
.itabs-radio:nth-of-type(3):checked ~ .itabs-bar label:nth-of-type(3),
.itabs-radio:nth-of-type(4):checked ~ .itabs-bar label:nth-of-type(4),
.itabs-radio:nth-of-type(5):checked ~ .itabs-bar label:nth-of-type(5),
.itabs-radio:nth-of-type(6):checked ~ .itabs-bar label:nth-of-type(6){color:var(--color-accent);border-bottom-color:var(--color-accent)}
.itabs-radio:nth-of-type(1):checked ~ .itabs-panels .itabs-panel--0,
.itabs-radio:nth-of-type(2):checked ~ .itabs-panels .itabs-panel--1,
.itabs-radio:nth-of-type(3):checked ~ .itabs-panels .itabs-panel--2,
.itabs-radio:nth-of-type(4):checked ~ .itabs-panels .itabs-panel--3,
.itabs-radio:nth-of-type(5):checked ~ .itabs-panels .itabs-panel--4,
.itabs-radio:nth-of-type(6):checked ~ .itabs-panels .itabs-panel--5{display:block;animation:itabs-fade .2s ease}
@keyframes itabs-fade{from{opacity:0}to{opacity:1}}
</style>

Props

Prop Type Default Beschrijving
tabs * { icon?: string; label: string; body: string }[] - Tab-items (label + paneeltekst). Ondersteunt tot 6 tabs.

* = verplicht