Lists are continuous, vertical indexes of text or images. They are composed of items containing primary and supplemental actions, which are represented by icons and text.
Basic list
A simple list with text items:
muiMaterialPage(
CssBaseline(
Box(
sx = list(width = "100%", maxWidth = 360, bgcolor = "background.paper"),
List(
ListItem(
ListItemButton(
ListItemIcon(shiny::icon("inbox")),
ListItemText(primary = "Inbox")
)
),
ListItem(
ListItemButton(
ListItemIcon(shiny::icon("paper-plane")),
ListItemText(primary = "Drafts")
)
)
)
)
)
)Nested list
A list with nested items and collapsible sections:
library(shiny)
library(muiMaterial)
muiMaterialPage(
CssBaseline(
Box(
sx = list(width = "100%", maxWidth = 360, bgcolor = "background.paper"),
List(
component = "nav",
ListItemButton(
ListItemIcon(shiny::icon("home")),
ListItemText(primary = "Home")
),
ListItemButton(
ListItemIcon(shiny::icon("envelope")),
ListItemText(primary = "Inbox"),
shiny::icon("chevron-down"),
onClick = JS("() => {
const el = document.getElementById('inbox-collapse');
if (el) {
el.style.display = el.style.display === 'none' ? 'block' : 'none';
}
}")
),
Collapse(
`in` = TRUE,
timeout = "auto",
unmountOnExit = TRUE,
id = "inbox-collapse",
List(
component = "div",
disablePadding = TRUE,
ListItemButton(
sx = list(pl = 4),
ListItemIcon(shiny::icon("star")),
ListItemText(primary = "Starred")
),
ListItemButton(
sx = list(pl = 4),
ListItemIcon(shiny::icon("clock")),
ListItemText(primary = "Snoozed")
)
)
),
ListItemButton(
ListItemIcon(shiny::icon("paper-plane")),
ListItemText(primary = "Drafts")
)
)
)
)
)List with dividers
Use Divider() to separate list items:
muiMaterialPage(
CssBaseline(
Box(
sx = list(width = "100%", maxWidth = 360, bgcolor = "background.paper"),
List(
component = "nav",
ListItem(
ListItemButton(
ListItemIcon(shiny::icon("inbox")),
ListItemText(primary = "Inbox")
)
),
Divider(),
ListItem(
ListItemButton(
ListItemIcon(shiny::icon("paper-plane")),
ListItemText(primary = "Drafts")
)
),
Divider(),
ListItem(
ListItemButton(
ListItemIcon(shiny::icon("trash")),
ListItemText(primary = "Trash")
)
)
)
)
)
)List with avatars
Combine lists with Avatar() components:
muiMaterialPage(
CssBaseline(
Box(
sx = list(width = "100%", maxWidth = 360, bgcolor = "background.paper"),
List(
ListItem(
ListItemAvatar(
Avatar(
alt = "Remy Sharp",
src = "https://mui.com/static/images/avatar/1.jpg"
)
),
ListItemText(
primary = "Remy Sharp",
secondary = "Available for chat"
)
),
ListItem(
ListItemAvatar(
Avatar(
alt = "Travis Howard",
src = "https://mui.com/static/images/avatar/2.jpg"
)
),
ListItemText(
primary = "Travis Howard",
secondary = "Busy - Do not disturb"
)
),
ListItem(
ListItemAvatar(
Avatar(
alt = "Cindy Baker",
src = "https://mui.com/static/images/avatar/3.jpg"
)
),
ListItemText(
primary = "Cindy Baker",
secondary = "Away"
)
)
)
)
)
)List with secondary action
Add secondary actions to list items using ListItemSecondaryAction():
muiMaterialPage(
CssBaseline(
Box(
sx = list(width = "100%", maxWidth = 360, bgcolor = "background.paper"),
List(
ListItem(
secondaryAction = IconButton(
edge = "end",
shiny::icon("comment")
),
ListItemAvatar(
Avatar(
alt = "Remy Sharp",
src = "https://mui.com/static/images/avatar/1.jpg"
)
),
ListItemText(
primary = "Remy Sharp",
secondary = "Jan 9, 2024"
)
),
ListItem(
secondaryAction = IconButton(
edge = "end",
shiny::icon("comment")
),
ListItemAvatar(
Avatar(
alt = "Travis Howard",
src = "https://mui.com/static/images/avatar/2.jpg"
)
),
ListItemText(
primary = "Travis Howard",
secondary = "Jan 7, 2024"
)
)
)
)
)
)Interactive list with reactRouter
Create an interactive navigation list with reactRouter R package:
library(muiMaterial)
library(reactRouter)
#>
#> Attaching package: 'reactRouter'
#> The following object is masked from 'package:muiMaterial':
#>
#> Link
muiMaterialPage(
CssBaseline(
HashRouter(
Box(
sx = list(display = "flex", height = "100vh"),
Box(
sx = list(width = 240, bgcolor = "background.paper", borderRight = "1px solid #e0e0e0"),
List(
component = "nav",
NavLink(
to = "/",
style = "text-decoration: none; color: black",
ListItemButton(
ListItemIcon(shiny::icon("home")),
ListItemText(primary = "Home")
)
),
NavLink(
to = "/inbox",
style = "text-decoration: none; color: black",
ListItemButton(
onClick = Navigate("/inbox"),
ListItemIcon(shiny::icon("inbox")),
ListItemText(primary = "Inbox")
)
),
NavLink(
to = "/starred",
style = "text-decoration: none; color: black",
ListItemButton(
onClick = Navigate("/starred"),
ListItemIcon(shiny::icon("star")),
ListItemText(primary = "Starred")
)
),
NavLink(
to = "/drafts",
style = "text-decoration: none; color: black",
ListItemButton(
ListItemIcon(shiny::icon("paper-plane")),
ListItemText(primary = "Drafts")
)
)
)
),
Box(
sx = list(flex = 1, p = 3),
Routes(
Route(
path = "/",
element = Typography("Home Page", variant = "h4")
),
Route(
path = "/inbox",
element = Typography("Inbox", variant = "h4")
),
Route(
path = "/starred",
element = Typography("Starred", variant = "h4")
),
Route(
path = "/drafts",
element = Typography("Drafts", variant = "h4")
)
)
)
)
)
)
)Selectable list
Create a list with selectable items:
library(shiny)
library(muiMaterial)
ui <- muiMaterialPage(
CssBaseline(
Box(
sx = list(width = "100%", maxWidth = 360, bgcolor = "background.paper", p = 2),
Typography("Select items:", variant = "h6", sx = list(mb = 2)),
uiOutput("selectable_list"),
Typography(
uiOutput("selected_message"),
variant = "body2",
sx = list(mt = 2)
)
)
)
)
server <- function(input, output, session) {
items <- c("Photos", "Work", "Vacation")
selected <- reactiveVal(character(0))
output$selectable_list <- renderUI({
List(
lapply(items, function(item) {
is_selected <- item %in% selected()
ListItem(
disablePadding = TRUE,
ListItemButton(
selected = is_selected,
onClick = JS(sprintf(
"() => Shiny.setInputValue('toggle_item', {item: '%s', time: Math.random()})",
item
)),
ListItemIcon(shiny::icon("folder")),
ListItemText(primary = item)
)
)
})
)
})
observeEvent(input$toggle_item, {
item <- input$toggle_item$item
if (item %in% selected()) {
selected(setdiff(selected(), item))
} else {
selected(c(selected(), item))
}
})
output$selected_message <- renderUI({
if (length(selected()) == 0) {
"No items selected"
} else {
paste("Selected:", paste(selected(), collapse = ", "))
}
})
}
shinyApp(ui, server)List with checkboxes
Add checkboxes to list items for multiple selection:
library(shiny)
library(muiMaterial)
ui <- muiMaterialPage(
CssBaseline(
Box(
sx = list(width = "100%", maxWidth = 360, bgcolor = "background.paper", p = 2),
Typography("To-do list:", variant = "h6", sx = list(mb = 2)),
uiOutput("checkbox_list")
)
)
)
server <- function(input, output, session) {
todos <- reactiveVal(list(
list(id = "1", text = "Buy groceries", checked = FALSE),
list(id = "2", text = "Walk the dog", checked = FALSE),
list(id = "3", text = "Finish report", checked = FALSE),
list(id = "4", text = "Call mom", checked = FALSE)
))
output$checkbox_list <- renderUI({
List(
lapply(todos(), function(todo) {
ListItem(
disablePadding = TRUE,
ListItemButton(
role = "undefined",
onClick = JS(sprintf(
"() => Shiny.setInputValue('toggle_todo', {id: '%s', time: Math.random()})",
todo$id
)),
dense = TRUE,
ListItemIcon(
Checkbox(
edge = "start",
checked = todo$checked,
tabIndex = -1,
disableRipple = TRUE
)
),
ListItemText(
primary = todo$text,
sx = if (todo$checked) list(textDecoration = "line-through") else NULL
)
)
)
})
)
})
observeEvent(input$toggle_todo, {
todo_id <- input$toggle_todo$id
current <- todos()
updated <- lapply(current, function(t) {
if (t$id == todo_id) {
t$checked <- !t$checked
}
t
})
todos(updated)
})
}
shinyApp(ui, server)List with switches
Add switches to list items for settings-style lists:
library(shiny)
library(muiMaterial)
ui <- muiMaterialPage(
CssBaseline(
Box(
sx = list(width = "100%", maxWidth = 360, bgcolor = "background.paper", p = 2),
Typography("Notifications:", variant = "h6", sx = list(mb = 2)),
uiOutput("settings_list")
)
)
)
server <- function(input, output, session) {
settings <- reactiveVal(list(
list(id = "wifi", label = "Wi-Fi", enabled = TRUE),
list(id = "bluetooth", label = "Bluetooth", enabled = FALSE),
list(id = "notifications", label = "Notifications", enabled = TRUE)
))
output$settings_list <- renderUI({
List(
lapply(settings(), function(setting) {
ListItem(
ListItemIcon(
if (setting$id == "wifi") shiny::icon("wifi")
else if (setting$id == "bluetooth") shiny::icon("bluetooth")
else shiny::icon("bell")
),
ListItemText(primary = setting$label),
Switch(
edge = "end",
checked = setting$enabled,
onChange = JS(sprintf(
"() => Shiny.setInputValue('toggle_setting', {id: '%s', time: Math.random()})",
setting$id
))
)
)
})
)
})
observeEvent(input$toggle_setting, {
setting_id <- input$toggle_setting$id
current <- settings()
updated <- lapply(current, function(s) {
if (s$id == setting_id) {
s$enabled <- !s$enabled
}
s
})
settings(updated)
})
}
shinyApp(ui, server)Dense list
Use the dense prop for more compact lists:
muiMaterialPage(
CssBaseline(
Box(
sx = list(width = "100%", maxWidth = 360, bgcolor = "background.paper"),
List(
dense = TRUE,
ListItem(
ListItemAvatar(
Avatar(
alt = "Remy Sharp",
src = "https://mui.com/static/images/avatar/1.jpg"
)
),
ListItemText(
primary = "Remy Sharp",
secondary = "Software Engineer"
)
),
ListItem(
ListItemAvatar(
Avatar(
alt = "Travis Howard",
src = "https://mui.com/static/images/avatar/2.jpg"
)
),
ListItemText(
primary = "Travis Howard",
secondary = "Product Manager"
)
),
ListItem(
ListItemAvatar(
Avatar(
alt = "Cindy Baker",
src = "https://mui.com/static/images/avatar/3.jpg"
)
),
ListItemText(
primary = "Cindy Baker",
secondary = "Designer"
)
)
)
)
)
)