Tableau de bord Shiny : construire un shinydashboard avec value boxes et onglets
Agencez un tableau de bord avec dashboardPage, naviguez avec un sidebarMenu, affichez des KPI avec des value et info boxes, et disposez des panneaux box() sur une grille.
Un tableau de bord Shiny est un habillage de mise en page par-dessus la réactivité que vous connaissez déjà. Cette leçon en construit un avec shinydashboard : le squelette dashboardPage(dashboardHeader, dashboardSidebar, dashboardBody), un sidebarMenu de liens menuItem reliés à des pages tabItems/tabItem, les value boxes et info boxes qui affichent les KPI, et des panneaux box() disposés sur une grille fluidRow/column. Elle se termine par le package de tableau de bord à choisir — shinydashboard, bs4Dash ou flexdashboard.
- Un tableau de bord est une mise en page, pas une nouvelle logique.
shinydashboardremplacefluidPage()pardashboardPage(); vos reactives,renderPlot()et tablesDTrestent exactement les mêmes. - Le squelette tient en trois parties.
dashboardPage(dashboardHeader(), dashboardSidebar(), dashboardBody())— une barre de titre, un menu à gauche et la zone de contenu. - Naviguez avec un
sidebarMenu(). ChaquemenuItem(..., tabName = "x")est relié à untabItem(tabName = "x", ...)dans le corps — les chaînestabNamedoivent correspondre exactement, sinon la page reste vide. - Les value boxes sont les tuiles KPI.
valueBoxOutput("id")dans le corps +output$id <- renderValueBox({ valueBox(value, subtitle, icon, color) })dans le server vous donne les cartes à grand chiffre dont un tableau de bord est connu.infoBox()suit le même schéma avec un rendu plus léger. box()groupe les panneaux. Enveloppez un graphique ou une table dansbox(title, status, solidHeader, collapsible, width)et placez les boxes dansfluidRow()+column()(oubox(width = )) — la grille à 12 colonnes que vous connaissez déjà.- Choisissez le package selon le besoin.
shinydashboard= classique et rapide ;bs4Dash= un rendu Bootstrap 4 moderne ;flexdashboard= un tableau de bord statique écrit en R Markdown.
Introduction
Vous avez construit des graphiques qui réagissent aux entrées, des tables triables et des téléversements de fichiers. Un tableau de bord, c’est la manière de les assembler — des KPI tout en haut, des graphiques et des tables en dessous, un menu sur le côté, le tout sur un seul écran soigné. Le point rassurant : un tableau de bord n’ajoute presque aucun nouveau R. C’est un package de mise en page qui vous donne un en-tête, une barre latérale et des panneaux stylés ; le code server qui les remplit est la réactivité que vous connaissez déjà.
L’outil standard est shinydashboard. Il remplace fluidPage() par dashboardPage() et vous remet trois briques de construction — un en-tête, un menu latéral et un corps de boxes — plus les value boxes qui font les cartes KPI à grand chiffre. Cette leçon parcourt le squelette, la navigation de la barre latérale aux onglets, les value et info boxes, et le conteneur box(), puis se termine par le moment de recourir plutôt à bs4Dash ou flexdashboard.
Le code de cette page n’est pas exécuté ici — une application Shiny a besoin d’une session R active, elle ne peut donc pas tourner dans une page web statique. Copiez n’importe quel bloc dans un fichier app.R et exécutez-le en local avec shiny::runApp() (ou cliquez sur Run App dans RStudio). Les tableaux de bord ont besoin du package supplémentaire, alors installez-le une fois avec install.packages("shinydashboard") et chargez-le aux côtés de shiny. Les exemples utilisent le jeu de données intégré mtcars, ils tournent donc tels quels.
Pas de R installé ? Exécutez un tableau de bord en direct dans votre navigateur — des value boxes et un graphique, rien à configurer. Ouvrir dans le Playground ▸
Le squelette dashboardPage
Une application shinydashboard change l’enveloppe de page. Au lieu de fluidPage(), le ui est un dashboardPage() avec trois arguments — et ce sont toujours les trois mêmes : un en-tête, une barre latérale et un corps.
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(title = "Car Dashboard"), # the top bar + app title
dashboardSidebar(), # the left menu (empty for now)
dashboardBody() # the content area (empty for now)
)
server <- function(input, output, session) { }
shinyApp(ui, server)Exécutez cela et vous obtenez l’habillage reconnaissable du tableau de bord : un en-tête coloré avec le titre à gauche, une barre latérale sombre repliable, et un corps clair en attente de contenu. dashboardHeader() contient le titre (et d’éventuels menus déroulants) ; dashboardSidebar() contient le menu de navigation ; dashboardBody() contient tout ce que l’utilisateur regarde. Tout le reste de cette leçon se place à l’intérieur de l’un de ces trois.
Les value boxes : les tuiles KPI
Les cartes pour lesquelles un tableau de bord est célèbre — un grand chiffre, une étiquette, une icône, une couleur — sont les value boxes. Elles suivent exactement l’appariement render/output que vous utilisez déjà pour les graphiques et les tables, juste avec leur propre paire de fonctions :
- dans le corps,
valueBoxOutput("id")réserve l’emplacement ; - dans le server,
output$id <- renderValueBox({ valueBox(...) })le remplit.
valueBox() prend la value principale, une étiquette subtitle, un icon et un color. Comme la valeur est calculée dans le server, elle peut lire n’importe quel reactive — le KPI se met donc à jour quand les données changent.
ui <- dashboardPage(
dashboardHeader(title = "Car Dashboard"),
dashboardSidebar(),
dashboardBody(
fluidRow(
valueBoxOutput("avg_mpg"),
valueBoxOutput("n_cars")
)
)
)
server <- function(input, output, session) {
output$avg_mpg <- renderValueBox({
valueBox(
value = round(mean(mtcars$mpg), 1), # the big number
subtitle = "Average MPG",
icon = icon("gas-pump"),
color = "blue"
)
})
output$n_cars <- renderValueBox({
valueBox(
value = nrow(mtcars),
subtitle = "Cars in dataset",
icon = icon("car"),
color = "green"
)
})
}L’appariement est toute la règle : un valueBoxOutput() dans le corps et un renderValueBox() correspondant dans le server, reliés par l’id partagé. Oubliez l’une des deux moitiés et la box n’apparaît jamais. Envelopper les sorties dans un fluidRow() dispose les cartes côte à côte ; chaque value box revendique par défaut 4 des 12 unités de la grille, de sorte que trois tiennent proprement sur une ligne. Le color accepte les habillages nommés du tableau de bord ("blue", "green", "red", "yellow", "purple", "aqua", et d’autres), et icon() prend n’importe quel nom Font Awesome.
infoBox() est la cousine plus légère. Même idée, une carte plus compacte avec l’icône dans une tuile colorée — remplacez valueBoxOutput/renderValueBox/valueBox par infoBoxOutput/renderInfoBox/infoBox :
output$margin <- renderInfoBox({
infoBox(
title = "Top speed",
value = paste0(max(mtcars$hp), " hp"),
icon = icon("bolt"),
color = "purple",
fill = TRUE # fill the whole box with colour
)
})Recourez aux value boxes pour les KPI vedettes en haut d’un tableau de bord ; utilisez les info boxes quand vous voulez une carte de métrique plus douce et plus compacte.

Les panneaux avec box()
En dehors de la rangée de KPI, chaque graphique, table et contrôle d’un tableau de bord se place généralement à l’intérieur d’un box() — le panneau à en-tête titré qui donne au tableau de bord son aspect net et encadré. Enveloppez n’importe quelle sortie dans box() et réglez quelques arguments :
title— le texte de l’en-tête ;status— la couleur de l’en-tête ("primary","success","warning","info","danger") ;solidHeader = TRUE— une barre d’en-tête pleine au lieu d’un mince trait coloré ;collapsible = TRUE— ajoute un bouton−/+pour que l’utilisateur puisse replier le panneau ;width— sa largeur de grille (sur 12), la même quecolumn().
dashboardBody(
fluidRow(
box(
title = "Horsepower vs MPG", status = "primary", solidHeader = TRUE,
width = 8, collapsible = TRUE,
plotOutput("scatter")
),
box(
title = "Summary", status = "info", solidHeader = TRUE,
width = 4,
tableOutput("summary")
)
)
)Chaque box() est une cellule de grille : width = 8 et width = 4 totalisent 12, donc le graphique prend les deux tiers de la ligne et le résumé un tiers. Vous disposez les boxes exactement comme vous avez disposé les colonnes dans les mises en page — un fluidRow() par ligne, des largeurs totalisant 12 — mais vous pouvez donner à chaque box() sa width directement au lieu de l’envelopper dans un column(). Mêlez les deux quand vous avez besoin d’un contrôle plus fin : un column() peut contenir une pile de boxes, et un box() peut contenir son propre fluidRow() d’entrées.
Le server ne change pas
Voici le point qui vaut d’être répété : un tableau de bord change la mise en page, pas la logique. Le server qui remplit un shinydashboard est le même server que vous écririez pour une application fluidPage(). Un graphique dans un box() est toujours un renderPlot() ; une table est toujours renderTable() ou DT::renderDataTable() ; les reactives, observeEvent() et req() se comportent tous à l’identique.
server <- function(input, output, session) {
output$scatter <- renderPlot({
plot(mtcars$hp, mtcars$mpg, pch = 19, col = "#3a86d4",
xlab = "Horsepower", ylab = "MPG")
})
output$summary <- renderTable({
data.frame(
Metric = c("Cars", "Avg MPG", "Max HP"),
Value = c(nrow(mtcars), round(mean(mtcars$mpg), 1), max(mtcars$hp))
)
})
}Rien ici n’est spécifique au tableau de bord — ce sont les graphiques interactifs et les tables de données que vous avez déjà construits, déposés dans des boxes. C’est pourquoi un tableau de bord est surtout un exercice de mise en page : apprenez les quatre conteneurs ci-dessus (dashboardPage, le menu latéral, les value boxes, box()) et vous pouvez réhabiller n’importe quelle application que vous avez faite en tableau de bord sans toucher à son cœur réactif.
Quel package de tableau de bord quand
shinydashboard est le défaut et le plus populaire, mais ce n’est pas la seule voie. Tous les trois produisent un tableau de bord ; ils diffèrent par le rendu et par la manière de les écrire.
| Package | Ce que c’est | Recourez-y quand |
|---|---|---|
shinydashboard |
Le tableau de bord classique de style AdminLTE — dashboardPage, value boxes, box(). |
Vous voulez un tableau de bord éprouvé et rapide avec la forme familière en-tête-barre latérale-corps. |
bs4Dash |
Une refonte moderne quasi compatible bâtie sur Bootstrap 4 — même API dashboardPage/box/value-box, style plus frais, cartes, mode sombre. |
Vous voulez un rendu contemporain et des composants Bootstrap 4, avec peu de changements de code. |
flexdashboard |
Une mise en page R Markdown statique — vous écrivez des titres ## dans un .Rmd, pas du code ui Shiny. |
Vous voulez un tableau de bord rapide de style rapport à partir d’un document (il peut intégrer du Shiny, mais c’est document-first). |
Commencez par shinydashboard — son API est celle que les autres empruntent, donc ce que vous apprenez ici se transfère. bs4Dash est l’étape naturelle suivante quand vous voulez un habillage plus moderne : les fonctions sont délibérément proches, donc vous ne changez souvent guère plus que library(shinydashboard) en library(bs4Dash). flexdashboard joue dans une tout autre catégorie — un document .Rmd où les tailles de panneaux viennent des titres Markdown — au mieux quand vous écrivez vraiment un rapport qui se trouve avoir des graphiques en direct.
Problèmes fréquents
Vous avez oublié library(shinydashboard). dashboardPage, valueBox, box et consorts vivent dans le package shinydashboard, pas dans shiny de base. Sans library(shinydashboard) en haut de app.R, l’application échoue avec could not find function "dashboardPage". Chargez les deux, shiny et shinydashboard, et installez le package une fois avec install.packages("shinydashboard") si ce n’est pas déjà fait.
Un clic de menu affiche une page vide — décalage de tabName. Le tabName d’un menuItem() doit correspondre au tabName de son tabItem() exactement, caractère pour caractère. menuItem(tabName = "overview") apparié à tabItem(tabName = "Overview") (ou une faute de frappe comme "overiew") laisse l’entrée de menu sans rien à afficher, donc le corps reste vide. Vérifiez que les deux chaînes s’alignent, et que chaque tabItem() vit à l’intérieur d’une unique enveloppe tabItems() dans le corps.
Une value box n’apparaît pas. Une value box a besoin de ses deux moitiés : valueBoxOutput("id") dans le dashboardBody() et output$id <- renderValueBox({ ... }) dans le server, avec le même id. N’écrivez que le renderValueBox() et il n’y a aucun emplacement à remplir ; n’écrivez que le valueBoxOutput() et l’emplacement reste vide. Confirmez que les ids correspondent et que le render renvoie un valueBox(...).
Questions fréquentes
Utilisez le package shinydashboard. Remplacez fluidPage() par dashboardPage(dashboardHeader(), dashboardSidebar(), dashboardBody()), mettez un sidebarMenu() de liens menuItem() dans la barre latérale et un ensemble tabItems()/tabItem() correspondant dans le corps, puis remplissez le corps de KPI valueBox() et de panneaux box(). Le server — vos reactives, renderPlot(), renderTable() — reste exactement le même qu’une application Shiny ordinaire.
shinydashboard est le package de tableau de bord classique, bâti sur le thème AdminLTE 2 / Bootstrap 3. bs4Dash est une refonte moderne sur Bootstrap 4 avec un rendu plus frais (cartes, mode sombre, plus de composants) et une API délibérément similaire — dashboardPage, box et les value boxes existent toujours, donc le portage ne demande souvent guère plus que de basculer library(shinydashboard) en library(bs4Dash). Choisissez shinydashboard pour le classique éprouvé, bs4Dash pour un style Bootstrap 4 contemporain.
Utilisez l’appariement value-box : mettez valueBoxOutput("id") dans le dashboardBody() et output$id <- renderValueBox({ valueBox(value, subtitle, icon = icon("..."), color = "blue") }) dans le server. La value est le grand chiffre, subtitle est l’étiquette, et comme elle est calculée dans le server elle peut lire n’importe quel reactive, le KPI se met donc à jour avec les données. infoBox() (avec infoBoxOutput/renderInfoBox) suit le même schéma avec un rendu plus léger.
Construisez-les en deux moitiés correspondantes. Dans dashboardSidebar(), ajoutez un sidebarMenu() avec un menuItem("Label", tabName = "x") par onglet ; dans dashboardBody(), ajoutez un bloc tabItems() avec un tabItem(tabName = "x", ...) par onglet. Les chaînes tabName doivent correspondre exactement — cliquer sur l’entrée de menu affiche le tabItem ayant le même tabName. Un décalage laisse la page vide.
Non. shinydashboard ne change que la mise en page du ui — la fonction server est identique à une application fluidPage(). Un graphique dans un box() est toujours un renderPlot(), une table est toujours renderTable() ou DT::renderDataTable(), et vos reactives, observeEvent() et req() fonctionnent tous sans changement. Un tableau de bord est un habillage de mise en page par-dessus la logique que vous avez déjà.
Testez vos connaissances
Construisez une application shinydashboard avec un menu latéral de deux onglets — « Overview » et « Data ». L’onglet Overview affiche deux value boxes : le nombre de lignes dans mtcars et sa moyenne mpg. L’onglet Data affiche une table de head(mtcars) dans un box(). Assurez-vous que chaque menuItem atteint son onglet.
Le squelette est dashboardPage(dashboardHeader(), dashboardSidebar(sidebarMenu(...)), dashboardBody(tabItems(...))). Donnez à chaque menuItem("Overview", tabName = "overview") un tabItem(tabName = "overview", ...) correspondant. Les value boxes ont besoin de valueBoxOutput() dans l’onglet et de renderValueBox() dans le server ; enveloppez la table dans box(title = ..., tableOutput("tbl")).
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(title = "mtcars Dashboard"),
dashboardSidebar(
sidebarMenu(
menuItem("Overview", tabName = "overview", icon = icon("gauge")),
menuItem("Data", tabName = "data", icon = icon("table"))
)
),
dashboardBody(
tabItems(
tabItem(
tabName = "overview",
fluidRow(
valueBoxOutput("n_cars"),
valueBoxOutput("avg_mpg")
)
),
tabItem(
tabName = "data",
box(title = "First rows of mtcars", status = "primary", solidHeader = TRUE,
width = 12, tableOutput("tbl"))
)
)
)
)
server <- function(input, output, session) {
output$n_cars <- renderValueBox({
valueBox(nrow(mtcars), "Cars in dataset", icon = icon("car"), color = "green")
})
output$avg_mpg <- renderValueBox({
valueBox(round(mean(mtcars$mpg), 1), "Average MPG", icon = icon("gas-pump"), color = "blue")
})
output$tbl <- renderTable({ head(mtcars) })
}
shinyApp(ui, server)Les chaînes tabName apparient les deux liens menuItem() à leurs pages tabItem() ; les value boxes utilisent l’appariement valueBoxOutput + renderValueBox ; et la table est un renderTable() ordinaire déposé dans un box() — la logique server n’est pas différente d’une application Shiny ordinaire.
Vous ajoutez menuItem("Sales", tabName = "sales") à votre barre latérale, et dans le corps vous écrivez tabItem(tabName = "Sales", ...). Cliquer sur « Sales » affiche une page vide. Pourquoi ?
A. menuItem et tabItem ne peuvent pas être utilisés ensemble. B. Les chaînes tabName ne correspondent pas — "sales" vs "Sales" — donc le clic n’a aucune page correspondante. C. Il vous faut un valueBox() avant qu’aucun tabItem() ne s’affiche. D. tabItem() doit aller dans la barre latérale, pas dans le corps.
B. Le tabName est le lien entre un menuItem et son tabItem, et il est mis en correspondance exactement — "sales" et "Sales" sont des chaînes différentes, donc le clic de menu ne trouve aucune page à afficher et le corps reste vide. A et D sont fausses (ils sont conçus pour fonctionner ensemble, tabItem appartient au corps à l’intérieur de tabItems()), et C n’a aucun rapport — les value boxes ne sont pas requises pour qu’un onglet s’affiche.
Conclusion
Un tableau de bord Shiny demande bien moins de nouveau code qu’il n’y paraît. Avec shinydashboard, vous remplacez fluidPage() par dashboardPage(dashboardHeader(), dashboardSidebar(), dashboardBody()), vous naviguez avec un sidebarMenu() de liens menuItem() reliés par tabName correspondant à des pages tabItems()/tabItem(), vous affichez les KPI avec l’appariement valueBoxOutput() + renderValueBox() (et infoBox() pour une carte plus légère), et vous encadrez chaque graphique ou table dans un box() placé sur la grille familière à 12 colonnes. Le server en dessous ne change jamais — un tableau de bord est un habillage de mise en page par-dessus la réactivité, les graphiques et les tables que vous connaissez déjà. Quand vous voulez un rendu plus moderne, bs4Dash emprunte la même API sur Bootstrap 4 ; pour un tableau de bord de style document, flexdashboard en écrit un en R Markdown.
Ensuite, vous ferez vivre le tableau de bord — en rafraîchissant ses chiffres sur une minuterie et en poussant les mises à jour à mesure que les données changent.
Leçons connexes
- Approfondissez : les téléversements de fichiers — la leçon précédente ; laissez les utilisateurs alimenter le tableau de bord avec leurs propres données dans ses boxes ; les graphiques interactifs et les tables de données — les graphiques et tables que vous déposez dans les panneaux
box(); les mises en page — la grillefluidRow/columnsur laquelle un tableau de bord dispose ses boxes. Puis les mises à jour en temps réel rafraîchissent le tableau de bord sur une minuterie. - Allez plus loin : Interactivité Shiny — la série complète. · Interface Shiny — la couche d’interface. · Science computationnelle et IA — le pilier.
Réutilisation
Citation
@online{2026,
author = {},
title = {Tableau de bord Shiny : construire un shinydashboard avec
value boxes et onglets},
date = {2026-06-28},
url = {https://www.datanovia.com/learn/programming/shiny/interactivity/dashboards},
langid = {fr}
}