Tables et listes
Les composants de données rendent les enregistrements de vos tables. Chacun se lie via le module partagé dataSource et rend les enregistrements correspondants. Le filtrage, le tri et la pagination appartiennent à dataSource, pas au composant — une table n'a ni filter ni sort de premier niveau.
- type: data-table
dataSource: { table: tasks, sort: [{ field: due_date, direction: asc }] }
columns:
- { field: title, sortable: true }
- { field: due_date, format: relative-date }data-table
| Propriété | Description |
|---|---|
dataSource |
Liaison de table. Porte filter, sort et pagination. |
columns |
Définitions de colonnes. Générées depuis les champs de la table si omises. |
selection |
Sélection de lignes. |
bulkActions |
Actions proposées une fois des lignes sélectionnées. |
groupBy |
Regroupement des lignes. Les en-têtes comptent l'ensemble des résultats, pas la page chargée. |
summary |
Agrégats de la grille — et de chaque groupe dès que la grille est groupée. |
toolbar |
Quels contrôles de barre d'outils afficher. |
rowHeight |
short, medium (défaut) ou tall. |
striped / bordered |
Alternance des fonds de lignes ; bordures de cellules. |
rowColorField |
Champ dont les couleurs d'options déclarées remplissent chaque ligne — voir ci-dessous. |
showRowNumbers |
Préfixe une colonne de numéros de ligne. |
emptyMessage / noMatchMessage |
Affiché quand la source ne renvoie rien ; quand une recherche ou un filtre exclut tout. |
onRowClick |
Action invoquée au clic sur une ligne. N'accepte que deux formes — voir ci-dessous. |
rowExpand |
Déplie une ligne en fiche complète. true, false ou un objet — voir ci-dessous. |
autoSave |
Comportement d'édition inline. Voir Sauvegarde automatique. |
search |
Configuration de la recherche dans la table. |
onRowClick
Un clic sur une ligne n'accepte que deux formes :
| Forme | Effet |
|---|---|
{ type: navigate, path } |
Navigue vers path. Les jetons $record.<champ> sont remplacés par les valeurs de la ligne cliquée. |
{ action: openDrawer, component } |
Ouvre le composant drawer voisin portant cet id. props.width optionnel remplace sa largeur pour ce déclencheur. |
onRowClick:
type: navigate
path: /deals/$record.idNoter que openDrawer se discrimine sur action, et non sur type.
Tous les autres types d'action — auth, crud, automation, filter,
toast, fetch — sont rejetés ici, car un clic sur une ligne ne les a
jamais exécutés. Les comportements plus riches relèvent des actions du drawer
ouvert, où l'ensemble des actions est disponible : ouvrir la fiche dans un
drawer, puis agir dessus depuis là.
rowExpand
Ouvrir la fiche complète d'une ligne est une propriété de la grille : ni composant voisin, ni id à maintenir en phase.
- type: data-table
dataSource: { table: deals }
rowExpand: true| Valeur | Effet |
|---|---|
true |
Les lignes se déplient en un panneau dont les champs sont dérivés de la table liée. |
false |
Pas de dépliage — équivaut à omettre la clé, ce qui permet de le désactiver sur place. |
{ fields?, canEdit?, title? } |
Restreint la liste des champs, rend le panneau en lecture seule et le nomme. |
Sans fields, le panneau affiche tous les champs déclarés de la table liée, dans l'ordre de déclaration — et non les columns visibles. Si tu déplies une ligne, c'est pour voir ce que la ligne ne peut pas montrer : dériver des colonnes rendrait le dépliage sans effet sur une grille qui affiche déjà tout. Chaque champ conserve les label et description qu'il déclare. Une liste fields explicite restreint et réordonne le panneau, et peut nommer un champ qui n'est pas une colonne.
- type: data-table
dataSource: { table: deals }
columns: [{ field: name }, { field: stage }]
rowExpand:
fields: [name, stage, notes]
canEdit: false
title: Détail de l'affairerowExpand et onRowClick ne peuvent pas être déclarés ensemble. Une ligne n'a qu'un clic, et deux réponses à ce qu'il déclenche forment une configuration dont les deux moitiés ne peuvent pas s'appliquer : elle est donc refusée plutôt que l'une l'emporte en silence. rowExpand: false aux côtés d'onRowClick reste valide, puisque false signifie « désactivé ».
rowExpand est également refusé sur une grille liée à un point de terminaison de lecture (dataSource.system ou systemSource) : le panneau dérive ses contrôles du schéma de champs de la table liée, et un point de terminaison de lecture n'en a pas. Utilise alors un record-drawer avec dataSource.system et ses propres recordFields, ouvert par onRowClick: { action: openDrawer, component }.
La forme câblée à la main — onRowClick: { action: openDrawer } plus un drawer voisin — reste inchangée et n'est pas dépréciée. rowExpand est un raccourci pour le cas courant, non un remplacement : le drawer peut toujours se lier à une autre table que celle de la grille, se lier à un point de terminaison de lecture, être partagé par deux grilles et porter des actions de pied de panneau.
Ce que signifie un clic
Une ligne peut porter plusieurs sens à la fois. C'est la cible qui tranche, jamais le minutage :
| Le clic atteint | Effet |
|---|---|
| Une cellule éditable | Le double-clic ouvre l'éditeur de cellule ; la fiche ne se déplie pas. |
| La case de sélection | Sélectionne la ligne, rien d'autre. |
| Un en-tête de groupe | Replie ou déplie ce groupe, à n'importe quel niveau d'imbrication. |
| Toute autre cellule | Déplie la fiche. |
Les lignes restent accessibles au clavier : une ligne portant une action est focalisable et répond à Entrée, sans qu'aucun bouton ne soit ajouté par ligne.
Cocher une case ne déclenche plus l'action de ligne. La case de sélection laissait auparavant passer son clic jusqu'à la ligne : sur toute grille dont les lignes portent une action — un navigate au clic autant qu'un dépliage — sélectionner des lignes pour agir en lot déclenchait aussi cette action. Sélectionner sélectionne, et c'est tout.
columns
Une colonne est soit une colonne de champ, soit une colonne d'actions (type: actions, portant actions, chacune { label, action, icon, confirm, visibleWhen, editSelect }).
| Propriété de colonne de champ | Description |
|---|---|
field |
Nom du champ dans la table liée. |
label |
Libellé d'en-tête de remplacement. |
width / minWidth |
Largeurs en pixels. |
align |
left (défaut), center, right. |
format |
Rendu de cellule : truncate, currency, percentage, compact, relative-date, relative-time, short-date, long-date, datetime, yes-no, check-cross. |
valueLabels |
Table valeur brute vers libellé affiché, p. ex. { todo: 'To do' }. |
frozen |
Fige la colonne afin qu'elle reste visible au défilement horizontal. |
visible |
false pour masquer la colonne. |
sortable / filterable / editable |
Bascules de capacité par colonne. |
cellStyle |
Règles { when: { <opérateur>: valeur }, className } appliquées par cellule. Opérateurs : eq, neq, in, notIn, contains, gt, lt, gte, lte. |
columns:
- field: status
frozen: true
cellStyle: [{ when: { eq: overdue }, className: 'text-red-600' }]
- type: actions
actions: [{ label: Delete, action: { type: crud, operation: delete, table: tasks } }]Sélection, regroupement et totaux
selection prend un mode obligatoire — none, single ou multiple — plus showCheckboxes. Chaque entrée de bulkActions vaut { label, icon, action, confirm }, où confirm est le texte du dialogue et peut contenir {count}, remplacé par le nombre de lignes sélectionnées.
groupBy accepte field, direction (asc par défaut), collapsed et thenBy — jusqu'à deux niveaux supplémentaires imbriqués dans le premier, trois au total. Chaque entrée de thenBy accepte les trois mêmes clés. summary accepte field, label et function — parmi count, sum, avg, min, max.
direction ordonne les en-têtes de groupe eux-mêmes, et non les lignes à l'intérieur d'un groupe : celles-ci suivent dataSource.sort et les en-têtes de colonnes. Un regroupement sur un champ à sélection unique ou de statut ordonne les en-têtes selon l'ordre déclaré des options plutôt qu'alphabétiquement : un stage valant prospect/qualified/won se lit donc dans l'ordre où il a été écrit. Chaque en-tête compte par ailleurs l'ensemble des résultats : un groupe de 30 enregistrements affiche (30) même sur une page qui n'en montre que 22 — et cela vaut à chaque niveau, si bien qu'un sous-groupe débordant d'une page annonce quand même sa taille complète.
Chaque niveau répond pour lui-même. direction s'applique par niveau et indépendamment : un niveau externe peut s'ouvrir dans l'ordre déclaré d'un pipeline pendant que le niveau imbriqué à l'intérieur se lit en desc, sans que l'un touche à l'autre. collapsed est également par niveau, et le repliement s'imbrique : replier un parent masque tout ce qui se trouve en dessous, en-têtes de sous-groupes compris. Un champ nommé par un niveau n'a pas besoin d'être une colonne visible ; l'en-tête en porte la valeur, ce qui est souvent la raison même de grouper dessus.
Nommer le même champ à deux niveaux est refusé à la validation : tous les enregistrements d'un groupe partagent déjà la valeur qui l'a formé, donc un niveau répété place exactement un sous-groupe dans chaque groupe et ne partitionne rien.
Un summary déclaré décrit la grille entière et, dès que la grille est groupée, il décrit en plus chaque groupe — à chaque niveau, et pas seulement au plus interne. Aucune seconde option n'est à activer : les totaux par groupe découlent du summary déjà déclaré, si bien qu'une grille associant groupBy et summary gagne un total par groupe sans qu'une ligne de configuration change. Les totaux d'un groupe restent visibles lorsqu'il est replié, ce qui rend le repliement général utile pour comparer les groupes.
Parce que chaque niveau est synthétisé, les chiffres se recomposent : une sum sur les sous-groupes d'un parent égale celle de ce parent, et celles des parents égalent celle du pied de tableau. C'est tout l'intérêt de l'imbrication — comparer un parent à ses enfants suppose que les deux soient calculés.
Comme le pied de tableau, un total de groupe décrit le groupe entier et non sa partie présente sur la page courante, et il s'affiche dans le format de sa colonne. Le pied de tableau continue de répondre pour la grille entière à leurs côtés : une vue groupée montre donc à la fois les chiffres par groupe à chaque profondeur et le chiffre global.
- type: data-table
dataSource: { table: deals }
pagination: { pageSize: 25 }
groupBy: { field: stage, direction: asc }
summary:
- { field: name, function: count, label: Affaires }
- { field: value, function: sum, label: Valeur du pipeline }Chaque étape rapporte son propre nombre d'affaires et sa valeur de pipeline, et le pied de tableau rapporte les deux toutes étapes confondues. Les totaux d'un groupe se placent sous la colonne qu'ils décrivent ; un total portant sur un champ qui n'est pas une colonne visible conserve sa valeur et s'affiche à côté du nom du groupe plutôt que d'être écarté.
L'imbrication ajoute des niveaux sans ajouter d'options — le même summary répond désormais à chacun d'eux :
- type: data-table
dataSource: { table: deals }
pagination: { pageSize: 25 }
groupBy:
field: region
direction: asc
thenBy:
- { field: stage, direction: desc }
- { field: owner, collapsed: true }
summary:
- { field: name, function: count, label: Affaires }
- { field: value, function: sum, label: Valeur du pipeline }Les régions se lisent dans leur ordre déclaré, les étapes de chaque région se lisent en sens inverse, et les responsables de chaque étape démarrent repliés. owner ne figure pas parmi les colonnes, et n'a pas besoin d'y figurer.
toolbar est une table de booléens sélectionnant les contrôles affichés : search, filters, sort, export, refresh, density, columnToggle, groupBy, views, viewSwitcher.
rowColorField
Désigne un champ dont les couleurs d'options déclarées remplissent chaque ligne — l'orthographe propre à la grille du colorField que lisent kanban, calendrier et chronologie. La clé s'appelle rowColorField et non colorField parce qu'une grille décide déjà d'une couleur par colonne : un colorField nu s'y lirait comme « colorer les cellules ».
- type: data-table
dataSource: { table: orders }
rowColorField: order_statusLa grammaire est celle des vues d'enregistrements : le remplissage provient des couleurs d'options déclarées sur le champ désigné, et la couleur du texte de la ligne en est dérivée afin de rester lisible sur n'importe quelle teinte.
Contrairement à un calendrier ou à une chronologie, une grille n'invente rien. Une valeur dont l'option ne déclare aucune couleur n'est pas remplie — il n'y a pas de palette de repli. Il en va de même pour une ligne dont la valeur est vide, et pour une grille sans rowColorField : ces trois cas restent simplement non remplis.
Une ligne remplie neutralise striped. L'alternance, le survol et la sélection sont tous peints comme fonds de ligne ; or, sur une ligne remplie, le fond appartient à l'auteur de l'application et non à l'habillage de la grille. Une ligne remplie abandonne donc ces trois fonds et porte sa sélection et son survol sous forme d'ombres internes — un liseré complet pour la sélection, un bord gauche pour le survol, tous deux dans la couleur dérivée du texte de la ligne.
La neutralisation vaut par ligne, pas par grille : une ligne non remplie, dans une grille qui déclare pourtant rowColorField, conserve exactement l'alternance, le survol et la sélection habituels.
Contrairement au colorField des vues d'enregistrements, celui-ci est vérifié. sovrium validate refuse un rowColorField désignant un champ absent de la table liée : une grille non remplie a la même apparence, que le nom soit une faute de frappe ou que les couleurs aient été volontairement laissées non déclarées.
list
Une liste verticale d'enregistrements. Toute la présentation vit sous listDisplay.
Propriété de listDisplay |
Description |
|---|---|
itemTemplate |
Modèle par enregistrement : title, subtitle, image, badge, metadata. |
loadMore |
button (un contrôle Charger plus) ou infinite (au défilement). |
highlight |
Met en évidence les termes de recherche trouvés. |
divider |
Trace des séparateurs entre les éléments. |
maxItems |
Plafond d'éléments affichés. |
emptyMessage |
Affiché quand rien ne correspond. |
metadata est un tableau de { field, format } rendu dans le pied de l'élément.
- type: list
dataSource: { table: articles, sort: [{ field: published_at, direction: desc }] }
listDisplay:
itemTemplate:
title: '$record.title'
metadata: [{ field: published_at, format: relative-date }]
loadMore: buttondata-form / form
Un formulaire adossé à un enregistrement. Les deux noms de type partagent un seul schéma. action décide de ce que fait la soumission ; fields surcharge le rendu de champs individuels.
| Propriété | Description |
|---|---|
dataSource |
Liaison de table — volontairement limitée aux tables, les écritures allant vers une table et jamais vers un point de terminaison de lecture. mode: single fournit les valeurs courantes d'un formulaire d'édition. |
fields |
Configuration par champ — field plus label, placeholder, control, options, defaultValue, readOnly, disabled, hidden, visibleWhen, requiredWhen, disabledWhen. |
fieldGroups |
Sections { label, fields } divisant le formulaire. |
layout |
single-column (défaut), two-column ou custom. |
action |
Ce que lance la soumission. Voir Interactions. |
- type: data-form
dataSource: { table: contacts, mode: single, param: id }
layout: two-column
action:
type: crud
operation: update
table: contacts
fields:
- { field: email, label: 'Email address' }
- { field: notes, control: textarea }gallery
Déplacé vers Tableaux, calendriers et chronologies.
kanban
Déplacé vers Tableaux, calendriers et chronologies.
calendar
Déplacé vers Tableaux, calendriers et chronologies.
data-timeline
Déplacé vers Tableaux, calendriers et chronologies.
chart
Déplacé vers Graphiques et KPI.
kpi
Déplacé vers Graphiques et KPI.
Pages connexes
- Liaison de données —
dataSource, filtres, pagination. - Sources système — lier une grille à un point de terminaison plateforme plutôt qu'à une table.
- Tableaux, calendriers et chronologies — les autres vues d'enregistrements.
- Graphiques et KPI — les visualisations agrégées.
- Contrôles de formulaire — les saisies qu'un formulaire héberge.
Dernière mise à jour 11 août 2026
Cette documentation a été rédigée avec de l'IA : des erreurs ou du contenu obsolète sont donc possibles. Sovrium est en bêta. Les contributions et corrections sont les bienvenues.