Services publics et administration · Nouvelle ressource
Système de design Aksel.
Utilisez les véritables tokens ax de Aksel v8, la densité native des tableaux et la structure sémantique de leurs en-têtes. Triez et sélectionnez des dossiers de suivi fictifs tout en comparant les thèmes clair et sombre.
Tableau natif Aksel 8.18.0 CSS et jetons avec HTML sémantique ; code local de tri et de sélection, et solution de repli explicite Arial. · Référence de mise en œuvre
02
Référence de conception du système de design Aksel
Feuille de style native @navikt/ds-css 8.18.0 examinée et documentation v8 actuelle. Les valeurs des modes clair et sombre sont contextualisées ; l’aperçu remplace les polices distantes par Arial et utilise les exemples de dossiers d’origine.
Ne mélangez pas les anciennes classes et les nouveaux jetons
La version v8 de Aksel utilise les jetons --ax-* et les classes de composants .aksel. Le guide de migration précise que les anciennes classes .navds ne fonctionnent plus et que les jetons propres aux composants ont été supprimés. Un tutoriel basé sur une ancienne capture d’écran peut donc sembler crédible tout en donnant des conseils d’implémentation erronés.
Cette page fixe la version native de CSS à 8.18.0 et fournit l’installation correspondante de React. L’aperçu utilise les classes natives de tableau examinées, avec un HTML ordinaire ; l’application JavaScript gère la sélection et le tri. Il ne prétend pas que le téléchargement d’une feuille de style instancie un composant Table de React.
Système de design Aksel : rôles typographiques et chargement des polices
Utilisez 600 pour le jeton de gras
La référence des jetons définit la pile de polices Source Sans 3, Source Sans Pro, Arial et sans-serif. Le poids normal est 400 et le jeton nommé pour le gras vaut 600. Les tailles de texte courant comprennent 14, 16, 18 et 20px ; les rôles de titre vont jusqu’à 24, 28, 32 et 40px.
L’aperçu local définit le jeton de police sur Arial et remplace explicitement toute police héritée, afin de ne faire aucune requête de police distante. Il s’agit d’un choix de police de repli déclaré, et non d’affirmer qu’Arial est la police principale du système de design Aksel. Le dimensionnement du texte des composants est toujours fourni par CSS.
Système de design Aksel : espacement, rayon et mise en page
Les jetons nommés en pixels correspondent à des valeurs en rem
--ax-space-16 vaut 1rem et --ax-space-24 vaut 1.5rem. La syntaxe des primitives v8 respecte ces noms : padding="space-16" et gap={{xs:"space-8",md:"space-16"}}. Ne remplacez pas ces valeurs par une ancienne propriété d’espacement numérique sans vérifier les consignes de migration.
Les rôles de rayon documentés comprennent 2, 4, 8, 12 et 16px, ainsi que la valeur full. L’aperçu conserve la géométrie native du tableau et utilise space-24 autour des commandes de l’application. La largeur de lecture de 64rem est un choix local ; les points de rupture proviennent de la feuille de style examinée.
Système de design Aksel : couleurs sémantiques adaptées au thème
Préservez le rôle, pas une valeur hexadécimale unique
La feuille de style native associe --ax-text-neutral à neutral-1000, soit #202733 en mode clair et #dfe1e5 en mode sombre. --ax-bg-default passe du blanc à #0e151f. Inscrire en dur la valeur de texte du mode clair dans un conteneur sombre annulerait la correspondance des rôles.
L’aperçu change la classe de thème .light/.dark et laisse les couleurs des bandes, des bordures et des lignes sélectionnées du tableau suivre les jetons officiels. La sélection reste indiquée par une case cochée et un compteur visible. Une ligne colorée ne suffit pas à constituer une interface de sélection.
Système de design Aksel : anatomie sémantique des tableaux
Les en-têtes ne sont pas des cellules ordinaires
Le tableau natif distingue les classes d’en-tête, de corps, de ligne, de cellule d’en-tête et de cellule de données. L’équivalent de React utilise Table.Header, Table.Body, Table.Row, Table.HeaderCell et Table.DataCell. La colonne de référence est un en-tête de ligne, et chaque en-tête de colonne possède scope=col.
La légende nomme la collection. Les jours d’attente sont des quantités et sont alignés à droite ; les identifiants de référence restent alignés à gauche. À faible largeur, l’aperçu conserve le défilement horizontal dans une zone nommée qui peut recevoir le focus clavier, plutôt que de dégrader les relations du tableau pour transformer les lignes en cartes.
Utilisez des cellules d’en-tête pour les libellés de colonnes comme pour les identifiants de ligne.
Alignez à droite les valeurs quantitatives, mais pas les codes postaux ni les identifiants.
Ajoutez une légende pour donner un nom explicite au tableau.
Dans le composant CSS natif inspecté, les cellules de densité moyenne utilisent space-12 verticalement et space-8 horizontalement. La densité faible utilise space-4 verticalement, et la densité élevée, space-16 verticalement. Le sélecteur de densité modifie la classe de modificateur native ; il ne réduit pas la taille de la police du corps pour faire tenir davantage d’informations dans la fenêtre.
L’en-tête « Jours d’attente » est un bouton de tri de style natif. Son gestionnaire trie les valeurs numériques et met à jour aria-sort sur cet en-tête. Cette transformation relève de l’application : le composant React API expose lui aussi l’état de tri et onSortChange, au lieu de trier automatiquement des enregistrements métier arbitraires.
Système de design Aksel — sélection des lignes accessible au clavier
Prévoir un contrôle explicite pour chaque ligne
La documentation de Table indique que onRowClick seul ne permet pas l’accessibilité au clavier. L’exemple fournit donc une case à cocher avec libellé pour chaque référence et une case pour tout sélectionner. La case globale passe à l’état indéterminé lorsqu’une partie seulement des lignes est sélectionnée.
Le tri préserve la sélection grâce à l’identifiant stable de la référence. Il n’utilise jamais l’index actuel de la ligne comme clé de sélection, car la coche se déplacerait vers un autre enregistrement lors d’un changement d’ordre. Le nombre d’éléments sélectionnés est mis à jour dans une région de statut avec annonce polie. Aucun enregistrement sélectionné n’est envoyé ailleurs.
Système de design Aksel — charger les CSS et React correspondants
Synchroniser les versions des paquets
Installez @navikt/ds-react et @navikt/ds-css à la même version, puis importez le CSS une seule fois, près de la racine de l’application. Le paquet inclut déjà les tokens de design. Le guide officiel d’importation de CSS prend également en charge les fichiers globaux et de composants importés séparément, mais les styles de base sont obligatoires et les polices et tokens doivent être fournis ou explicitement remplacés.
Aksel utilise les couches CSS. Évitez les sélecteurs généraux hors couche, qui risquent de remplacer accidentellement les styles des composants. Les mises en page personnalisées de l’application doivent utiliser vos propres classes. L’aperçu autonome utilise des CSS locales et versionnées ainsi qu’une police délibérément remplacée ; l’exemple React présente un parcours d’intégration distinct, vérifié à partir des sources.
Verrouillez ensemble les versions des paquets React et CSS.
Importez la feuille de style une seule fois et utilisez les enfants sémantiques de Table pour le rendu.
Gérez le tri et la sélection dans l’état de l’application.
Vérifiez le changement de thème, les commandes au clavier et la zone de défilement étroite.
Le document complet comprend sa mise en page, ses contrôles et son initialisation. Extrayez l’archive d’exemple liée pour obtenir les ressources de fournisseur avec leurs chemins relatifs exacts, puis servez le contenu via HTTP.
html
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Aksel table workbench</title><link rel="stylesheet" href="vendor/aksel-8.18.0/index.css"><style>:root{--ax-font-family:Arial,sans-serif}body,body *,body *:before,body *:after{font-family:Arial,sans-serif!important}body{background:var(--ax-bg-default);color:var(--ax-text-neutral);font-size:18px;line-height:1.5}main{max-width:64rem;padding:32px 24px;margin:auto}h1{font-size:32px;font-weight:600;line-height:1.25;margin:16px 0 24px}p{margin:16px 0}.toolbar{display:flex;gap:24px;flex-wrap:wrap;padding:24px;background:var(--ax-bg-sunken);margin:24px 0}select{font-size:16px;padding:8px;background:var(--ax-bg-input);color:var(--ax-text-neutral);border:1px solid var(--ax-border-neutral)}label{font-size:16px;display:flex;gap:8px;align-items:center}.scroll{overflow-x:auto}table{min-width:38rem}caption{text-align:left;font-weight:600;margin-bottom:16px}input[type=checkbox]{width:20px;height:20px;accent-color:var(--ax-bg-accent-strong);cursor:pointer}small{font-size:14px;display:block;margin-top:24px;color:var(--ax-text-neutral-subtle)}:focus-visible{outline:3px solid var(--ax-border-focus);outline-offset:3px}@media(max-width:767px){main{padding:24px 16px}.toolbar{padding:16px;gap:16px}h1{font-size:28px}}</style><body class="light"><main><p>AKSEL v8 · NATIVE TABLE CSS</p><h1>Follow-up record workbench</h1><p>Compare density and theme while sorting and selecting fictional records. Selection follows each reference when the rows move.</p><div class="toolbar"><label>Density <select id="density"><option value="medium">Medium</option><option value="small">Small</option><option value="large">Large</option></select></label><label>Theme <select id="theme"><option value="light">Light</option><option value="dark">Dark</option></select></label></div><p id="selection" role="status">0 records selected</p><div class="scroll" tabindex="0" role="region" aria-label="Fictional follow-up records, horizontally scrollable"><table class="aksel-table aksel-table--zebra-stripes" id="records"><caption>Fictional follow-up records</caption><thead class="aksel-table__header"><tr class="aksel-table__row"><th class="aksel-table__header-cell" scope="col"><input id="all" type="checkbox" aria-label="Select all records"></th><th class="aksel-table__header-cell" scope="col">Reference</th><th class="aksel-table__header-cell" scope="col">Next activity</th><th class="aksel-table__header-cell" id="sort-header" scope="col" aria-sort="ascending"><button id="sort" type="button" class="aksel-table__sort-button">Waiting days ↑</button></th></tr></thead><tbody class="aksel-table__body" id="rows"></tbody></table></div><small>OpenDesign specimen using native Aksel 8.18.0 CSS and an explicit Arial fallback. Fictional data, no NAV identity or external actions.</small></main><script>const data=[{id:'DEMO-204',activity:'Confirm appointment preference',days:4},{id:'DEMO-218',activity:'Read the submitted example note',days:12},{id:'DEMO-231',activity:'Arrange an example callback',days:7}];let ascending=true;const selected=new Set(),all=document.querySelector('#all');function render(){const body=document.querySelector('#rows');body.replaceChildren();for(const r of [...data].sort((a,b)=>ascending?a.days-b.days:b.days-a.days)){const tr=document.createElement('tr');tr.className='aksel-table__row'+(selected.has(r.id)?' aksel-table__row--selected':'');const td=document.createElement('td');td.className='aksel-table__data-cell';const c=document.createElement('input');c.type='checkbox';c.setAttribute('aria-label','Select '+r.id);c.checked=selected.has(r.id);c.onchange=()=>{c.checked?selected.add(r.id):selected.delete(r.id);updateSelection();tr.classList.toggle('aksel-table__row--selected',c.checked)};td.append(c);const th=document.createElement('th');th.scope='row';th.className='aksel-table__header-cell';th.textContent=r.id;const activity=document.createElement('td');activity.className='aksel-table__data-cell';activity.textContent=r.activity;const days=document.createElement('td');days.className='aksel-table__data-cell aksel-table__data-cell--align-right';days.textContent=r.days;tr.append(td,th,activity,days);body.append(tr)}updateSelection()}function updateSelection(){all.checked=selected.size===data.length;all.indeterminate=selected.size>0&&selected.size<data.length;document.querySelector('#selection').textContent=selected.size+' records selected'}all.onchange=()=>{selected.clear();if(all.checked)data.forEach(r=>selected.add(r.id));render()};document.querySelector('#sort').onclick=()=>{ascending=!ascending;document.querySelector('#sort-header').setAttribute('aria-sort',ascending?'ascending':'descending');document.querySelector('#sort').textContent='Waiting days '+(ascending?'↑':'↓');render()};document.querySelector('#density').onchange=e=>document.querySelector('table').className='aksel-table aksel-table--zebra-stripes aksel-table--'+e.target.value;document.querySelector('#theme').onchange=e=>document.body.className=e.target.value;render();</script></body></html>
Téléchargez l’exemple complet depuis les sources. Son fichier README indique la commande exacte pour le lancer localement.
Conservez des chemins relatifs pour les ressources de fournisseur par rapport à ce document ; l’archive contient toutes les ressources utilisées par cet aperçu.
04
Configuration de l’agent du système de design Aksel
Point de départ de l’implémentation
Le composant natif CSS 8.18.0 est rendu localement dans l’aperçu. La composition React a été vérifiée à partir des sources, mais n’a pas fait l’objet d’une compilation distincte. Alignez les versions ; ne combinez pas les classes navds v7 avec CSS v8. Le fichier ZIP d’exemple fonctionnel complet, disponible dans Sources, fournit également les dépendances exactes de l’aperçu et le document complet. Extrayez-le, exécutez python3 -m http.server 8080 dans ce répertoire, puis ouvrez http://localhost:8080/nav-aksel.html. N’ouvrez pas les exemples utilisant des modules avec file://.
Créez une table sémantique Aksel v8 avec les paquets CSS/React 8.18.0 correspondants. Conservez la légende, les en-têtes de colonnes et les en-têtes de lignes de référence. Utilisez les véritables tokens ax et les propriétés de primitives space-*. Prévoyez le tri numérique avec aria-sort, la sélection par cases à cocher fondée sur des identifiants stables et une case « tout sélectionner » à l’état indéterminé. Ne comptez pas sur onRowClick pour les interactions au clavier. Prenez en charge les tokens de rôle clair/sombre et une zone de défilement horizontal avec libellé sur les écrans étroits.
05
Sources et périmètre du système de design Aksel
Enregistrements d’exemple indépendants, sans identité NAV. La feuille de style native est utilisée avec une police de remplacement déclarée. Le tri, la sélection et la mise en page relèvent de l’application ; aucune donnée réelle sur les prestations ou les dossiers n’est présentée.