Install
#remotes::install_github("lgnbhl/muiTreeView") # development version
install.packages("muiTreeView")Basic examples
MUI Rich Tree View
Use RichTreeView() with the asMuiTree()
helper function:
df <- data.frame(
pkg = c("muiTreeView", "muiTreeView", "muiTreeView"),
functions = c("SimpleTreeView", "RichTreeView", "RichTreeView"),
args = c("items", "items", "onItemSelectionToggle")
)
treeItems <- asMuiTree(df)
RichTreeView(
items = treeItems
)Multi selection and checkbox
You can activate checkbox selection with
checkboxSelection = TRUE and multi selection with
multiSelect = TRUE:
RichTreeView(
items = treeItems,
checkboxSelection = TRUE,
multiSelect = TRUE # FALSE for single select
)Add data with asMuiTree()
The helper function asMuiTree() transforms your
dataframe in a structure which can be used with
RichTreeView().
You can provide a vector of the column names to select and choose the level order of the tree nodes, for example:
df <- data.frame(
pkg = c("muiTreeView", "muiTreeView", "muiTreeView"),
functions = c("SimpleTreeView", "RichTreeView", "RichTreeView"),
args = c("items", "items", "onItemSelectionToggle")
)
treeItems <- asMuiTree(df, c("functions", "pkg"))
str(treeItems, max.level = 3)
#> List of 2
#> $ :List of 3
#> ..$ label : chr "SimpleTreeView"
#> ..$ id : chr "SimpleTreeView-7030611"
#> ..$ children:List of 1
#> .. ..$ :List of 2
#> $ :List of 3
#> ..$ label : chr "RichTreeView"
#> ..$ id : chr "RichTreeView-3110731"
#> ..$ children:List of 1
#> .. ..$ :List of 2asMuiTree() creates also unique IDs for each node by
joining the name of the label with an random integer between a dash.
df <- data.frame(
pkg = c("muiTreeView", "muiTreeView", "muiTreeView"),
functions = c("SimpleTreeView", "RichTreeView", "RichTreeView"),
args = c("items", "items", "onItemSelectionToggle")
)
treeItems <- asMuiTree(df, c("functions", "pkg"))
# treeItems <- list(
# list(
# label = "muiTreeView", id = "muiTreeView-1",
# children = list(
# list(
# label = "SimpleTreeView", id = "SimpleTreeView-2",
# children = list(
# list(label = "items", id = "items-3")
# )
# ),
# list(
# label = "RichTreeView", id = "RichTreeView-4",
# children = list(
# list(label = "items", id = "items-5"),
# list(label = "onItemClick", id = "onItemClick-6")
# )
# )
# )
# )
# )
RichTreeView(
items = treeItems
)As asMuiTree() is adapted from shinyWidgets::create_tree(),
I want to thank the authors of shinyWidgets for their amazing work!
Rich Tree View default selection and expand
Select by default one or multiple items with the
defaultSelectedItems argument by providing its related
IDs.
You can also expand by default one or multiple nodes with the
defaultExpandedItems argument by providing its related
IDs.
df <- data.frame(
pkg = c("muiTreeView", "muiTreeView", "muiTreeView"),
functions = c("SimpleTreeView", "RichTreeView", "RichTreeView"),
args = c("items", "items", "onItemSelectionToggle")
)
treeItems <- asMuiTree(df)
defaultSelectedId <- treeItems[[1]]$children[[1]]$children[[1]]$id
defaultExpandedId_1 <- treeItems[[1]]$children[[1]]$id
defaultExpandedId_2 <- treeItems[[1]]$id
RichTreeView(
items = treeItems,
defaultSelectedItems = list(defaultSelectedId), # always in list()
defaultExpandedItems = list(defaultExpandedId_1, defaultExpandedId_2) # always in list()
)Custom styling
As muiTreeView is using the Material UI library under the hood, you can customize component styles using CSS classes with the “sx” argument:
RichTreeView(
items = treeItems,
sx = list(
".MuiTreeItem-root" = list(
".Mui-selected, .Mui-selected:hover, .Mui-focused.Mui-selected" = list(
background = "red",
color = "white"
)
)
)
)Note that even if the CSS classes are deprecated they are still working.
You can access all Material UI components using the shinyMaterialUI R package.
Simple Tree View
Using SimpleTreeView() with TreeItem(), you
can easily customize items with icons for example:
library(htmltools)
SimpleTreeView(
defaultExpandedItems = list("documents"), # always in list()
defaultSelectedItems = list("notes"), # always in list()
TreeItem(
itemId = "documents",
label = div(shiny::icon("folder"), " Documents"),
TreeItem(
itemId = "notes",
label = div(shiny::icon("file"), " Notes")
),
TreeItem(
itemId = "images",
label = div(shiny::icon("image"), " Images"),
sx = list(
".Mui-selected, .Mui-selected:hover, .Mui-focused.Mui-selected" = list(
background = "lightgreen",
color = "white"
)
)
),
TreeItem(
itemId = "videos",
label = div(shiny::icon("video"), " Videos"),
sx = list(
".Mui-selected, .Mui-selected:hover, .Mui-focused.Mui-selected" = list(
background = "lightblue",
color = "white"
)
)
)
),
TreeItem(
itemId = "history",
label = div(shiny::icon("history"), " History")
),
TreeItem(
itemId = "trash",
label = div(shiny::icon("trash"), " Trash")
)
)Usage with Shiny
You can get user item clicked in Shiny using the
onItemSelectionToggle argument (more info here),
by creating a “itemSelection” input with
shiny.react::setInput().
As the “itemSelection” input returns the label name followed by a
dash “-” with a random integer, you can get the cleaned label using
gsub(),
i.e. gsub(pattern = "\\-.*$", replacement = "", x = input$itemSelection)
Track latest item clicked
library(shiny)
df <- data.frame(
pkg = c("muiTreeView", "muiTreeView", "muiTreeView"),
functions = c("SimpleTreeView", "RichTreeView", "RichTreeView"),
args = c("items", "items", "onItemSelectionToggle")
)
treeItems <- asMuiTree(df)
defaultExpanded <- treeItems[[1]]$id
defaultSelectedId <- treeItems[[1]]$children[[1]]$id
ui <- tagList(
reactOutput("tree"),
#verbatimTextOutput("treeId"),
verbatimTextOutput("treeLabel")
)
server <- function(input, output, session) {
output$tree <- renderReact({
RichTreeView(
items = treeItems,
# expand by default a node with its id
defaultSelectedItems = list(defaultSelectedId), # always in list()
defaultExpandedItems = list(defaultExpanded), # always in list()
onItemSelectionToggle = setInput(
inputId = "itemSelection",
jsAccessor = "[1]"
)
)
})
# Reproduce logic from official MUI's documentation
selectedItems <- reactiveValues(
selected = defaultSelectedId
)
observeEvent(input$itemSelection, {
current_selection <- input$itemSelection
if(current_selection %in% selectedItems$selected) {
# Remove if already selected
new_selection <- setdiff(selectedItems$selected, current_selection)
} else {
# Add if not selected
new_selection <- c(selectedItems$selected, current_selection)
}
selectedItems$selected <- new_selection
})
# output$treeId <- shiny::renderPrint(
# # return item label with tree ID (not cleaning with gsub())
# selectedItems$selected
# )
output$treeLabel <- shiny::renderPrint(
# remove dash "-" followed by a random digit (i.e. MUI tree ID) to return only item label
gsub(pattern = "\\-[[:digit:]]*$", replacement = "", x = selectedItems$selected)
)
}
shinyApp(ui, server)
Track multiple items with checkbox selection
You can use reactive values to get multiple items selection by implementing the logic as showed in the official MUI documentation.
library(shiny)
df <- data.frame(
pkg = c("muiTreeView", "muiTreeView", "muiTreeView"),
functions = c("SimpleTreeView", "RichTreeView", "RichTreeView"),
args = c("items", "items", "onItemSelectionToggle")
)
treeItems <- asMuiTree(df)
defaultExpandedId <- treeItems[[1]]$id
defaultSelectedId <- treeItems[[1]]$children[[1]]$children[[1]]$id
ui <- tagList(
reactOutput("tree"),
#verbatimTextOutput("treeId"),
verbatimTextOutput("treeLabel")
)
server <- function(input, output, session) {
output$tree <- renderReact({
RichTreeView(
checkboxSelection = TRUE,
multiSelect = TRUE,
items = treeItems,
# expand by default a node with its id
defaultExpandedItems = list(defaultExpandedId), # always in list()
defaultSelectedItems = list(defaultSelectedId), # always in list()
# By default, selecting a item does not select its children.
selectionPropagation = list(
descendants = TRUE
),
onItemSelectionToggle = shiny.react::setInput(
inputId = "itemSelection",
jsAccessor = "[1]"
)
)
})
# Reproduce logic from official MUI's documentation
selectedItems <- reactiveValues(
selected = defaultSelectedId
)
observeEvent(input$itemSelection, {
current_selection <- input$itemSelection
if(current_selection %in% selectedItems$selected) {
# Remove if already selected
new_selection <- setdiff(selectedItems$selected, current_selection)
} else {
# Add if not selected
new_selection <- c(selectedItems$selected, current_selection)
}
selectedItems$selected <- new_selection
})
# output$treeId <- shiny::renderPrint(
# # return item label with tree ID (not cleaning with gsub())
# selectedItems$selected
# )
output$treeLabel <- shiny::renderPrint(
# remove dash "-" followed by a random digit (i.e. MUI tree ID) to return only item label
gsub(pattern = "\\-[[:digit:]]*$", replacement = "", x = selectedItems$selected)
)
}
shinyApp(ui, server)
More features
Explore the official MUI Tree View documentation to see how more features can be added.
Use other MUI products
MUI X Tree View is developed MUI, the company behind the popular React framework Material UI. muiTreeView is therefore a companion to the R package shinyMaterialUI , which provides access to all Material UI components from R.
Bootstrap conflict
muiTreeView can enter in conflict with the Bootstrap
CSS framework, used by default in Shiny functions such as
shiny::fluidPage() and friends.
The Bootstrap conflict could potentially be solved using Shadow DOM.
Contribute
If you have any issue, question or want to contribute with a pull request, don’t hesitate to write me on https://github.com/lgnbhl/muiTreeView
For updates follow Felix Luginbuhl on LinkedIn.