ADR-035 ActifActive contract

`agtc-card` implementation

DateDate
2026-05-31
DécideursDecision makers
Design System Lead

Reference UX patterns applied

Added on 2026-06-01 via the ux-pattern-review workflow (ADR-036). Decision: C1, C3, C4 approved; C2 revised (anti-nesting clickability rule). Details and links: guidelines/components/card.md § REFERENCE UX PATTERNS.

PatternSource
Clustering of related contentDashboard — grouped layout
Clickable card — C2 revised (1 destination = enclosing link; distinct actions = ::after overlay or non-interactive container; never nested interactive elements)Smashing — clickable cards · NN/g
Hierarchy via elevation/shadow, not color aloneDashboard — composition
Detail-on-demand (the card summarizes)Dashboard — screenspace

Context

agtc-card is a visual container for grouping related information. It's one of the most-used components in interfaces — it structures dashboards, result lists, and grouped forms.

Two questions guided the decisions:

1. Interactivity — a card can be clickable (link to a detail view) or purely a container. Should this behavior be encoded into the component?

2. Sections — header, body, footer are recurring patterns. Should they be structurally enforced or left free via slots?


Decisions

Decision 1 — No native interactivity in v1

A clickable card is a complex accessibility pattern: the interactive element must be <a> or <button>, not a <div> with onclick.

Decision: agtc-card is non-interactive. For a clickable card, the consumer places an <a> or <agtc-button> inside. An agtc-card-link component could be added in v2 if the need recurs.

Rejected alternative: adding a clickable attribute with tabindex="0" and role="button" — rejected because a <div role="button"> with no native <button> is a WCAG 4.1.2 anti-pattern (interactive elements must use semantic HTML elements).


Decision 2 — Named header / footer slots with automatic separators

The header and footer slots are detected via slotchange + assignedNodes(). Separators (border) only appear if the slot is actually used — avoiding an orphaned border on a card with no header.

Padding on the header/body/footer sections is uniform (same value as the padding attribute) so the spacing stays visually consistent.

Exception: has-header and has-footer remove the body's padding-top when a header is present, and its padding-bottom when a footer is present — avoiding double spacing at the joints.


Decision 3 — 3 variants: default / elevated / flat

VariantUsageVisual signal
defaultStandard cardSubtle gray border
elevatedHighlighted, hierarchySoft drop shadow
flatGrouped background, integrated sectionSubtle gray background, no border

The elevated shadow (0 1px 3px rgba(0,0,0,0.10)) is encoded as a component token, card.elevated.shadow. There isn't yet a semantic elevation token — this token is a proxy until a dedicated elevation system is created.


Decision 4 — 4 padding levels: none / sm / md / lg

none is indispensable for cards with full-width images. sm (12px) for compact cards (tables, dense lists). md (20px, default) for most cases. lg (24px) for cards with heavy text content.


v1 scope

IncludedExcluded (v2)
3 variantsagtc-card-link (clickable card)
4 padding levelsSkeleton loading state
header / body / footer slotsCard grid layout helper
Automatic separatorsoutlined-accent variant

Tokens added to component.json

TokenValue
--agtc-card-elevated-shadow0 1px 3px rgba(0,0,0,0.10), 0 1px 2px rgba(0,0,0,0.06)
--agtc-card-elevated-bordertransparent
--agtc-card-flat-backgroundgray-3 (#f0f0f0)
--agtc-card-flat-bordertransparent
--agtc-card-padding-none0px
--agtc-card-padding-sm12px
--agtc-card-padding-lg24px

Patterns UX de référence appliqués

Ajouté le 2026-06-01 via le workflow ux-pattern-review (ADR-036). Décision : C1, C3, C4 approuvés ; C2 révisé (règle de cliquabilité anti-imbrication). Détail et liens : guidelines/components/card.md § PATTERNS UX DE RÉFÉRENCE.

PatternSource
Clustering du contenu liéDashboard — grouped layout
Carte cliquable — C2 révisé (1 destination = lien englobant ; actions distinctes = overlay ::after ou conteneur non interactif ; jamais d'interactif imbriqué)Smashing — clickable cards · NN/g
Hiérarchie via élévation/ombre, pas couleur seuleDashboard — composition
Détail-on-demand (la carte résume)Dashboard — screenspace

Contexte

agtc-card est un conteneur visuel pour regrouper des informations liées. C'est l'un des composants les plus utilisés dans les interfaces — il structure les tableaux de bord, les listes de résultats, les formulaires groupés.

Deux questions ont guidé les décisions :

1. Interactivité — une carte peut être cliquable (lien vers un détail) ou purement contenante. Faut-il encoder ce comportement dans le composant ?

2. Sections — header, body, footer sont des patterns récurrents. Faut-il les imposer structurellement ou les laisser libres via slots ?


Décisions

Décision 1 — Pas d'interactivité native dans v1

Une carte cliquable est un pattern d'accessibilité complexe : l'élément interactif doit être <a> ou <button>, pas un <div> avec onclick.

Décision : agtc-card est non interactif. Pour une carte cliquable, le consommateur place un <a> ou <agtc-button> à l'intérieur. Un composant agtc-card-link pourrait être ajouté en v2 si le besoin est récurrent.

Alternative rejetée : ajouter un attribut clickable avec tabindex="0" et role="button" — rejeté car un <div role="button"> sans <button> natif est un anti-pattern WCAG 4.1.2 (les éléments interactifs doivent utiliser des éléments HTML sémantiques).


Décision 2 — Slots nommés header / footer avec séparateurs automatiques

Les slots header et footer sont détectés via slotchange + assignedNodes(). Les séparateurs (border) n'apparaissent que si le slot est réellement utilisé — évite un border orphelin sur une card sans header.

Le padding des sections header/body/footer est uniforme (même valeur que l'attribut padding) pour que l'espacement soit cohérent visuellement.

Exception : has-header et has-footer suppriment le padding-top du body quand un header est présent, et le padding-bottom quand un footer est présent — évite le double espacement aux jointures.


Décision 3 — 3 variantes : default / elevated / flat

VarianteUsageSignal visuel
defaultCarte standardBord gris subtil
elevatedMise en avant, hiérarchieOmbre portée douce
flatFond groupé, section intégréeFond gris subtil, pas de bord

La shadow de elevated (0 1px 3px rgba(0,0,0,0.10)) est encodée comme token composant card.elevated.shadow. Il n'existe pas encore de token sémantique d'élévation — ce token est un proxy jusqu'à la création d'un système d'élévation dédié.


Décision 4 — 4 niveaux de padding : none / sm / md / lg

none est indispensable pour les cartes avec images pleine largeur. sm (12px) pour les cartes compactes (tableaux, listes denses). md (20px, défaut) pour la majorité des cas. lg (24px) pour les cartes à fort contenu textuel.


Périmètre v1

InclusExclu (v2)
3 variantesagtc-card-link (carte cliquable)
4 niveaux de paddingSkeleton loading state
Slots header / body / footerCard grid layout helper
Séparateurs automatiquesVariante outlined-accent

Tokens ajoutés dans component.json

TokenValeur
--agtc-card-elevated-shadow0 1px 3px rgba(0,0,0,0.10), 0 1px 2px rgba(0,0,0,0.06)
--agtc-card-elevated-bordertransparent
--agtc-card-flat-backgroundgray-3 (#f0f0f0)
--agtc-card-flat-bordertransparent
--agtc-card-padding-none0px
--agtc-card-padding-sm12px
--agtc-card-padding-lg24px
← ADR-034 ADR-036 →