SOLCOM Button-System: vier dedizierte SDC-Komponenten + geteiltes Pillen-CSS
button, button-link, button-anchor, button-badge) plus ein gemeinsames Pillen-CSS-Layer. Shadcn-Variants werden ersatzlos entfernt.
Kontext
Das Figma-Design-System der SOLCOM-Site (figma.com/design/CHHDfbpX8Ys2LBiGs5HVK0, Node 766:15037 „Buttons") definiert fünf Button-Typen × vier States: Primary (Lime-Pille mit Brand-Pfeil), Link (nackter Text-Link mit Brand-Pfeil), Link with Icon (wie Link, aber mit funktionalem Icon wie Bell), Anchor (Lime-Pille mit Chevron-down) und Badge (Lime-Pille mit Notification-Counter). Die States sind Default / Hover / Focus / Disabled. Schrift ist ScalaSansLF-Bold 19 px, Pillen-Geometrie h-48, px-[18px], rounded-[30px].
Der bestehende components/button/button.twig (aus dem Byte-Theme-Fork, siehe ADR-0001) bietet vier shadcn-Variants (primary | secondary | primary-inverted | secondary-inverted) und drei Sizes — keine davon entspricht dem SOLCOM-Brand. ADR-0003 hat das Brand-Color-Mapping etabliert, aber explizit festgehalten, dass die SOLCOM-spezifischen Button-States nicht implementiert sind. Existierende Components components/anchor/ (Drupal-In-Page-Anker mit <span id>) und components/badge/ (Standalone-Label mit optionaler URL) tragen Namen, die im Figma anders belegt sind — sie machen konzeptionell etwas anderes.
Entscheidung
B-pur': vier dedizierte SDC-Komponenten plus geteiltes Pillen-CSS-Layer. Konkret:
components/button/wird auf die SOLCOM-Pille (Primary) reduziert; alle vier shadcn-Variants und diesize-Prop werden ersatzlos entfernt. Replace, nicht additiv.- Drei neue Komponenten:
components/button-link/(kein Pillen-Chrome, Lime-Text + Brand-Pfeil),components/button-anchor/(Pille + Chevron-down trailing) undcomponents/button-badge/(Pille + Counter trailing). - Existierende
components/anchor/undcomponents/badge/bleiben unangetastet; die Naming-Kollision wird in Kauf genommen, weil die Figma-Typen visuell denselben Pillen-Body wie Primary haben und dort gehören, wo die anderen Button-Geschwister stehen. - Die Pillen-Optik (Geometrie, States, Schrift, Hover/Focus/Disabled-Verhalten) lebt in einer geteilten CSS-Layer (
@layer componentsinsrc/theme.css), die alle drei Pillen-Komponenten per Klassen-Composition ziehen. - Focus-State per
outlinemitoutline-offset: 2px+outline: 2px solid var(--brand-lime), nicht per Tailwind-ring-Utility (box-shadow-basiert). Hover und Focus teilen das BG-Switch-Verhalten zur Weiß-Pille (Primary/Anchor/Badge); Link/LinkWithIcon haben kein BG-Switch und nur die Border-Markierung. - Brand-Pfeil als eigenes Custom-Icon-Set
solcom(icons/solcom/arrow-right.svg), parallel zum Phosphor-Set. Bell und Chevron-down werden weiter aus Phosphor bezogen. - Schrift:
ScalaSansWebweight 700 (das Web-Subset-Pendant zu ScalaSansLF-Bold, siehe ADR-0001). - Pillen-Geometrie ist fix: keine Multi-Size-Achse, kein
width/mobile_width-Prop. Full-width viabtn_classes: 'w-full'-Override am Caller. button-anchorwird als Scroll-to-Section (<a href="#{{ target }}">) interpretiert.button-badgeist interaktiv (<button>oder<a>), Schemarequired: [label, count], plus optionalcount_labelfür ARIA undhreffür Anchor-Render. Counter rendert nicht beicount = 0, kappt bei> 99auf99+.- Die Pille ist explizit für Dark-Background-Kontexte (Page-BG =
--brand-bg-blue). Lime auf Weiß scheitert WCAG 2.1 AA Kontrast (~1.28:1 statt 3:1). Light-Context-Pillen sind out of scope dieses ADRs. - Aufrufer-Migration in derselben PR:
navbar.twig:77(variant raus),navbar.twig:90(aufbyte_theme:button-linkumgestellt),card-pricing.twig:1-2(button_variant-Switch raus). Der Highlight-State der Pricing-Card wechselt sein Card-BG von Lime auf Brand-Dark-Blue, damit die Lime-Pille nicht mit dem Hintergrund verschmilzt.
Rejected alternatives
B-hybrid: alle fünf Typen als Variants in button.twig rejected
Spart Files, erzwingt aber Conditional Schema-Props (count nur sinnvoll wenn trailing=counter). Site-Builder hätten zwei oder drei Achsen statt einer Entscheidung. Mapping zu Figma-Library bricht.
B-pur ohne geteiltes CSS-Layer rejected
Vier SDC-Komponenten, jedes mit dupliziertem State-CSS. DRY-Verlust groß genug, um Refactor in 6 Monaten teuer zu machen.
Additiv: solcom als fünfte Variant neben shadcn-Variants rejected
Führt phantom Variants im Schema, die in Figma keinen Pendant haben. Site-Builder mit ~80 % Wahrscheinlichkeit fallen auf nicht-Brand-konforme Defaults oder können zwischen vier visuell unkommunizierten Werten nicht sicher wählen.
Multi-Size (small | medium | large) rejected
Figma zeigt nur eine Pillen-Größe; null von drei produktiven Aufrufern nutzt heute small oder large. Variant-für-niemanden-Anti-Pattern.
Phosphor-Pfeil statt Custom-Brand-Pfeil rejected
Visueller Drift zur SOLCOM-Visual-Identity. Der Brand-Pfeil ist erkennbar anders als ein generic Pfeil und Teil der Brand-Sprache.
button-anchor als Dropdown-Trigger mit ARIA-Disclosure-Logik rejected
Figma zeigt keinen Open-State (kein Chevron-up als Pendant), und die Dropdown-Mechanik wäre eine eigene Component-Klasse (disclosure/), nicht eine Button-Variante.
Pricing-Card aus dieser PR rausziehen rejected
Hätte den Card-BG-Konflikt verschoben, aber: der bestehende card-pricing.twig:2 referenziert weiter variant: 'primary-inverted', das nach Replace nicht mehr existiert — sofortiger Render-Fehler. Migration ist nicht trennbar.
Tone-Variante einführen (tone: 'on-light') rejected
Bricht die Fix-Size-Linie und B-pur-Reinheit, ist effektiv ein Step zurück zu Variants. Sinnvoller, das Light-Context-Problem als eigene Brand-Definition vom Designteam einzuholen.
Consequences
- Pillen-Body ist Single-Source-of-Truth, Focus-State aber zweigeteilt. Im Pillen-CSS-Layer sind zwei Focus-Klassen nötig: eine für Primary/Anchor/Badge (
outline-2 outline-brand-lime outline-offset-2+bg-white text-brand-dark-blue), eine für Link/LinkWithIcon (nuroutline-2 outline-brand-lime, kein BG-Switch). Beide Klassen leben in derselben Layer-Datei mit explizitem Kommentar. - Die Pille funktioniert nicht in jedem Kontext. Lime-Outline und Lime-Text auf weißem oder hellem Hintergrund scheitert WCAG 2.1 AA (Lime auf Weiß ≈ 1.28:1). Das CSS-Layer trägt einen prominenten Kommentar. Light-Context-Pille ist eigenes Folge-PR mit Designteam-Input.
- Pricing-Card-Highlight ändert visuell. Heute (nach ADR-0003-Mapping): Lime-Card mit Dark-Blue-Pille. Neu: Dark-Blue-Card mit Lime-Pille. Card-Text wechselt Dark-Blue → Weiß. Designer:innen sollten das post-merge gegenchecken.
button-anchor-Semantik ist Best-Guess (Scroll-to-Section). Die Annahme stützt sich auf das bestehendecomponents/anchor/und auf das Fehlen eines Open-State-Chevron-up im Figma. Wenn die Designer-Intention „Dropdown" war, istbutton-anchorein Wegwerfprodukt.- Custom-Icon-Set
solcomist neuer Pflegegegenstand. Aktuell ein einziges Asset (arrow-right.svg). Bei Wachstum: Pipeline für SVG-Optimierung und Icon-Update-Workflow nachschärfen. - Schema-Bruch in
button.component.yml:variantundsizeentfallen,requiredschrumpft auf[label]. Layout-Builder-Konfigurationen, die auf alte Variant-Werte referenzieren, würden bei Re-Render scheitern —drush config:export-Diff im Smoke-Test verifiziert. - Cherry-Pick-Reibung gegenüber Upstream-Byte-Theme steigt. Für
button.twigist der Cherry-Pick-Vertrag aus ADR-0001 mit dieser Entscheidung gebrochen — Upstream-Änderungen am Button-Schema müssen manuell gegen die SOLCOM-Pille gemappt werden. - Hover- und Focus-Verhalten sind visuell ähnlich (Primary/Anchor/Badge wechseln beide auf Weiß-Pille), aber CSS-Selektoren sind getrennt (
hover:undfocus-visible:). Konsolidierung wäre möglich, aber Klarheit beim Lesen geht vor Token-Sparen. - Browser-Baseline für
outline-offsetmitborder-radiusist Safari 16.4+/Chrome 111+/Firefox 113+ — identisch zu der bereits in ADR-0003 dokumentierten Baseline fürcolor-mix(). Kein neuer Browser-Support-Constraint. - Drupal-SDC-
#variantkollidiert mit der Byte-Theme-Konventionvariantals Style-Prop. Das Drupal-Render-Element#type => 'component'setzt inComponentElement::getInfo()einen Default'#variant' => ''und injiziert diesen inpreRenderComponent()alsprops['variant']. Das Byte-Theme nutztvariantals regulären Style-Prop mitenum— der leere String fällt durch die Schema-Validation. Konsequenzen für die Test-Strategie: Tests rendern SDCs konsequent über#type => 'inline_template'mit Twig-include, nicht über#type => 'component'. Sobald die Replace-Migration denvariant-Prop ausbutton.component.ymlentfernt hat, verschwindet der Konflikt für die Button-Komponente.
FAQ
- Warum nicht eine Komponente mit allen Typen als Variants?
- Conditional Schema-Props (z. B.
countnur bei Badge sinnvoll) erzeugen ein unklares Interface. Figma-Typen sind konzeptionell getrennte Elemente — vier Komponenten spiegeln das sauber wider. - Was ist mit Light-Background-Buttons?
- Out of scope. Lime auf Weiß scheitert WCAG 2.1 AA (~1.28:1). Eigenes Folge-PR nach Designteam-Input für
tone: 'on-light'oder eine separate Light-Pille.