You can add URL pages in Quarto document or R shiny like so:
library(reactRouter)
HashRouter(
NavLink(to = "/", "Main"),
NavLink(to = "/analysis", "Analysis"),
Routes(
Route(path = "/", element = "Main content"),
Route(path = "/analysis", element = "Analysis content")
)
)
A minimal example using shiny.
library(shiny)
library(reactRouter)
ui <- HashRouter(
NavLink(to = "/", "Main"),
shiny::br(),
NavLink(to = "/other", "Other"),
Routes(
Route(
path = "/",
element = uiOutput(outputId = "uiMain")
),
Route(
path = "/other",
element = uiOutput(outputId = "uiOther")
)
)
)
server <- function(input, output, session) {
output$uiMain <- renderUI( { p("Content home") } )
output$uiOther <- renderUI( { p("Other content") })
}
shinyApp(ui = ui, server = server)
A minimal example using bslib.
library(reactRouter)
library(bslib)
library(htmltools)
reactRouter::HashRouter(
bslib::page_navbar(
title = "reactRouter with bslib",
nav_item(
reactRouter::NavLink(
"Home",
to = "/"
)
),
nav_item(
reactRouter::NavLink(
"Analysis",
to = "/analysis"
)
),
reactRouter::Routes(
reactRouter::Route(
path = "/",
element = div(
tags$h3("Home page"),
p("A basic example of reactRouter with bslib.")
)
),
reactRouter::Route(
path = "/analysis",
element = "Content analysis"
),
reactRouter::Route(path = "*", element = "Custom error 404")
)
)
)
A minimal example using shinyMaterialUI.
# remotes::install_github("lgnbhl/shinyMaterialUI")
library(shinyMaterialUI)
HashRouter(
Box(
sx = list(flexGrow = 1),
AppBar(
position = "static",
Toolbar(
Typography(
variant = "h6",
component = "div",
sx = list(mr = 1),
"shinyMaterialUI"
),
NavLink(
to = "/",
Button(
color = "inherit",
"Home"
)
),
NavLink(
to = "analysis",
Button(
color = "inherit",
"Analysis"
)
)
)
),
Box(
reactRouter::Routes(
reactRouter::Route(
path = "/",
element = Box("Home page", sx = list(p = 1))
),
reactRouter::Route(
path = "/analysis",
element = Box("Content analysis", sx = list(p = 1))
),
reactRouter::Route(path = "*", element = "Error 404")
)
)
)
)
Find more examples with shinyMaterialUI here.
# adapted from example of shiny.router
# https://github.com/Appsilon/shiny.router/tree/main/examples/shiny_modules
library(shiny)
library(reactRouter)
# This creates UI for each page.
page <- function(title, content, id) {
ns <- NS(id)
div(
titlePanel(title),
p(content),
textOutput(ns("click_me"))
)
}
# Both sample pages.
root_page <- page("Home page", "Home page clicks", "root")
second_page <- page("Other page", "Other page clicks", "second")
server_module <- function(id, clicks, power = 1) {
moduleServer(id, function(input, output, session) {
output$click_me <- renderText({
as.numeric(clicks())^power
})
})
}
# Create output for our router in main UI of Shiny app.
ui <- reactRouter::HashRouter(
NavLink(to = "/", "Main"), br(),
NavLink(to = "/other", "Other"),
actionButton("clicks", "Click me!"),
Routes(
Route(
path = "/",
element = div(
root_page
)
),
Route(
path = "/other",
element = div(
second_page
)
)
)
)
# Plug router into Shiny server.
server <- function(input, output, session) {
clicks <- reactive({
input$clicks
})
server_module("root", clicks = clicks, power = 1)
server_module("second", clicks = clicks, power = 2)
}
# Run server in a standard way.
shinyApp(ui, server)
As React Router provides client routing, you can easily create multiple routes in a Quarto or R markdown documents:
# code to run in a Quarto document
# example adapted from: https://github.com/remix-run/react-router/tree/dev/examples/basic
library(reactRouter)
library(htmltools)
Layout <- div(
# A "layout route" is a good place to put markup you want to
# share across all the pages on your site, like navigation.
tags$nav(
tags$ul(
tags$li(
reactRouter::Link(to = "/", "Home")
),
tags$li(
reactRouter::Link(to = "/dashboard", "Dashboard")
),
tags$li(
reactRouter::Link(to = "/nothing-here", "Nothing Here")
)
)
),
tags$hr(),
# An <Outlet> renders whatever child route is currently active,
# so you can think about this <Outlet> as a placeholder for
# the child routes we defined above.
reactRouter::Outlet()
)
reactRouter::HashRouter(
div(
style = "border:1px solid black;", # add border just for the example
h1("Basic Example"),
tags$p(
paste0('This example demonstrates some of the core features of React Router
including nested reactRouter::Route(), reactRouter::Outlet(),
reactRouter::Link(), and using a "*" route (aka "splat route")
to render a "not found" page when someone visits an unrecognized URL.'
)
),
reactRouter::Routes(
Route(
path = "/",
element = Layout,
Route(
index = TRUE,
element = div(
tags$h2("Home"),
tags$p("Home content")
)
),
Route(
path = "dashboard",
element = div(
tags$h2("Dashboard"),
tags$p("Dashboard here")
)
),
# Using path="*"" means "match anything", so this route
# acts like a catch-all for URLs that we don't have explicit
# routes for.
Route(
path = "*",
element = div(
tags$h2("Nothing to see here!"),
tags$p(
Link(to = "/", "Go to the home page")
)
)
)
)
)
)
)
A minimal example using dynamic segments, i.e. using
Route(to = ":id/*")
.
library(shiny)
library(reactRouter)
library(bslib)
ui <- HashRouter(
bslib::page(
Link(
to = "/",
h3("reactRouter with dynamic routes", class = "m-3"),
style = "text-decoration: none; color: black"
),
Routes(
Route(
path = "/",
element = div(
# tags$a() necessary to observe `url_hash` in session
NavLink(
to = "project/1/overview",
"Project 1"
),
tags$br(),
NavLink(
to = "project/2/overview",
"Project 2"
)
)
),
Route(
path = "project/:id/*",
element = div(
NavLink(
to = "overview",
"Overview"
),
tags$br(),
NavLink(
to = "analysis",
"Analysis"
),
Outlet()
),
children = list(
reactRouter::Route(
path = "overview",
element = uiOutput("uiOverview")
),
reactRouter::Route(
path = "analysis",
element = uiOutput("uiAnalysis")
)
)
)
)
)
)
server <- function(input, output, session) {
url_hash <- shiny::reactiveVal(value = NA)
# update reactive values based on url hash
observeEvent(session$clientData$url_hash, {
current_url_hash <- session$clientData$url_hash
print(current_url_hash)
url_hash(current_url_hash)
})
output$uiOverview <- renderUI({
url_hash()
})
output$uiAnalysis <- renderUI({
url_hash()
})
}
shinyApp(ui, server)
Run a more advanced example of dynamic routes with:
reactRouter implements React Router v.6.30.0.
More info about how to use React Router can be found in the official website.