Skip to content

Menu

Extending

The grammar your own components follow to stay on-system.

Extending keel — the grammar

New components follow the same contract the shipped ones do:

  • Names follow k-block__element--modifier (BEM) — drop the k- prefix for your own so it's clear what shipped and what didn't.
  • Components consume tokens, never raw values. No hex colors, no pixel paddings — every visual decision points at the tokens layer, so your component rethemes with the rest of the page.
  • Expose your own knobs with token defaults — var(--my-knob, var(--k-token)) — so others can retheme your component the same way you retheme keel's.

A complete worked recipe — a testimonial component, defined in this page's own style block and rendered live below:

.testimonial {
  background: var(--k-surface);
  border: 1px solid var(--k-border);
  border-radius: var(--k-radius-l);
  padding: var(--k-space-5);
}
.testimonial__quote {
  font-size: var(--k-text-l);
  color: var(--k-text-soft);
  margin: 0 0 var(--k-space-3);
}
.testimonial__name {
  font-family: var(--k-font-mono);
  font-size: var(--k-text-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--k-text-faint);
}

Twelve lines of CSS, and it already looks like it shipped with the framework — because it's written in the same words.

a satisfied prototype

This is the same grammar keel itself is written in; read keel.css and you already know how to extend it.

Where you take over

keel ships zero JavaScript, so the styling layer stops where scripting begins. Dropdowns, tooltips, toasts, and carousels are covered above with native details, a CSS attribute, popover, and scroll-snap — trade-offs stated. A few things are yours to wire up:

  • Tab panel switching. .k-tabs ships the bar; point it at separate pages, pair it with a .k-accordion, or write the three lines of JavaScript for panel-switching yourself.
  • Form submission. keel styles fields and validation states; what happens on submit — client-side or otherwise — is yours.
  • Modal triggers. The base layer styles dialog and .k-drawer; the one line of showModal() wiring is yours to write.