Basic Multipage Routing Tutorial for Shiny Apps: shiny.router

By:
Dario Radečić
November 24, 2020

<h2><span data-preserver-spaces="true">Basic Routing for Shiny Web Applications</span></h2> <span data-preserver-spaces="true">Web applications couldn't exist without routing. Think about it in terms of the Appsilon website - you've visited our home page, navigated to the blog, and opened this particular article. </span><strong><span data-preserver-spaces="true">That's routing in a nutshell - matching UI components to a URL.</span></strong> <span data-preserver-spaces="true">Appsilon released the open source <code>shiny.router</code> package back in </span><a class="editor-rtfLink" href="https://wordpress.appsilon.com/shiny-router-package/" target="_blank" rel="noopener noreferrer"><span data-preserver-spaces="true">late 2018</span></a><span data-preserver-spaces="true">, and just recently version 0.2.0 went live on CRAN. This version fixed some bugs, augmented existing functionality a bit, and made a few important changes. In this article, we'll walk you through the version 0.2.0 update and show you how to create navbars using shiny.router. </span> <span data-preserver-spaces="true">You can download the source code for this article <a href="https://appsilon.com/wp-content/uploads/2020/11/shiny_router_code.zip" target="_blank" rel="noopener noreferrer">here</a>.</span> <ul><li><a href="#introduction">Introducing shiny.router</a></li><li><a href="#create-navbars">Creating Navigation Bars with shiny.router</a></li><li><a href="#styling">Styling Navigation Bars</a></li><li><a href="#conclusion">Conclusion</a></li></ul> <span data-preserver-spaces="true">To learn more about Appsilon's open source packages, see our new </span><a class="editor-rtfLink" href="http://shiny.tools/" target="_blank" rel="noopener noreferrer"><span data-preserver-spaces="true">Open Source Landing Page:</span></a><span data-preserver-spaces="true"> </span> <a href="http://shiny.tools"><img class="size-large wp-image-5332" src="https://wordpress.appsilon.com/wp-content/uploads/2020/09/Screen-Shot-2020-09-23-at-5.02.14-PM-1024x504.png" alt="Appsilon's shiny.tools landing page for our open source packages." width="1024" height="504" /></a> <em>Appsilon's shiny.tools landing page for our open source packages.</em> <h2 id="introduction"><span data-preserver-spaces="true">Introducing shiny.router</span></h2> <span data-preserver-spaces="true">At Appsilon, we routinely build </span><a class="editor-rtfLink" href="http://demo.appsilon.ai/" target="_blank" rel="noopener noreferrer"><span data-preserver-spaces="true">Shiny applications</span></a><span data-preserver-spaces="true"> for Global 2000 companies. The problem of routing is one of the first ones we encounter on every project. It made sense to develop an open-source package that handles it with ease. After all, routing is a common component of any web application and behaves identically in most projects.</span> <span data-preserver-spaces="true">Displaying the app's content on multiple pages can be achieved via tabsets, subpages of a dashboard. There was no easy way to direct users to a specific subpage via URL for a long time. Recently some </span><a class="editor-rtfLink" href="https://twitter.com/_ColinFay/status/1325833800090324992?s=19" target="_blank" rel="noopener noreferrer"><span data-preserver-spaces="true">alternative</span></a><span data-preserver-spaces="true"> solutions started to emerge, but the <code>shiny.router</code> remains the easiest one.</span> <span data-preserver-spaces="true">We have used <code>shiny.router</code> in many commercial projects, so we can confirm it is a field-tested solution. Also, many large organizations have adopted it as a solution on their own.</span> <span data-preserver-spaces="true">The latest version of the package is available on </span><a class="editor-rtfLink" href="https://cran.r-project.org/web/packages/shiny.router/index.html" target="_blank" rel="noopener noreferrer"><span data-preserver-spaces="true">CRAN</span></a><span data-preserver-spaces="true">, so the installation couldn't be any easier:</span> <pre><code class="language-r">install.packages("shiny.router")</code></pre> <span data-preserver-spaces="true">The new version (0.2.0) was released on the 30th October 2020, and it brought new documentation and functionalities and fixed existing issues. You can read the full changelog </span><a class="editor-rtfLink" href="https://github.com/Appsilon/shiny.router/blob/master/CHANGELOG.md" target="_blank" rel="noopener noreferrer"><span data-preserver-spaces="true">here</span></a><span data-preserver-spaces="true">.</span> <blockquote><strong>See some impressive Example Shiny Apps in our <a href="http://demo.appsilon.ai" target="_blank" rel="noopener noreferrer">Shiny Demo Gallery</a></strong></blockquote> <h2 id="create-navbars"><span data-preserver-spaces="true">Creating Navigation Bars with shiny.router</span></h2> <span data-preserver-spaces="true">To show how <code>shiny.router</code> works in practice, we'll develop a simple dashboard with a couple of routes. Every route will have a dummy text, showing us which route we're on.</span> <span data-preserver-spaces="true">To start, we'll import both <code>shiny</code> and <code>shiny.router</code>:</span> <pre><code class="language-r">library(shiny) library(shiny.router)</code></pre> <span data-preserver-spaces="true">Next, we will store content for three pages in three variables. Every page has a <code>shiny.titlePanel</code> and a paragraph:</span> <pre><code class="language-r">home_page &lt;- div(  titlePanel("Dashboard"),  p("This is a dashboard page") ) <br>settings_page &lt;- div(  titlePanel("Settings"),  p("This is a settings page") ) <br>contact_page &lt;- div(  titlePanel("Contact"),  p("This is a contact page") )</code></pre> <span data-preserver-spaces="true">We can then make a router and attach each of the pages with its corresponding route. The dashboard is located on the root page, so it will be the first one you see:</span> <pre><code class="language-r">router &lt;- make_router(  route("/", home_page),  route("settings", settings_page),  route("contact", contact_page) )</code></pre> <span data-preserver-spaces="true">The rest of the Shiny app is more or less what you would expect. We have to declare the <code>UI</code>, which contains a list of routes that enable us to navigate between pages. The <code>server</code> function passes input, output, and session data to the router. Finally, the call to <code>shinyApp</code> brings these two components together.</span> <pre><code class="language-r">ui &lt;- fluidPage(  tags$ul(    tags$li(a(href = route_link("/"), "Dashboard")),    tags$li(a(href = route_link("settings"), "Settings")),    tags$li(a(href = route_link("contact"), "Contact"))  ),  router$ui ) <br>server &lt;- function(input, output, session) {  router$server(input, output, session) } <br>shinyApp(ui, server)</code></pre> <span data-preserver-spaces="true">As a result, we have the following web application:</span> <img class="wp-image-6031 size-full" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b021a427d7e18d985649f6_001-1.gif" alt="Unstyled Shiny Router App" width="888" height="282" /> Unstyled Shiny Router App <span data-preserver-spaces="true">The application gets the job done but is quite basic with regards to the styling. Let's fix that next.</span> <h2 id="styling"><span data-preserver-spaces="true">Styling Navigation Bars</span></h2> <span data-preserver-spaces="true">You can add styles to your Shiny applications <a href="https://appsilon.com/howto-css-and-shiny/" target="_blank" rel="noopener noreferrer">with CSS</a>. To do so, create a <code>www</code> folder where your R script is, and create a CSS file inside it. We've named ours <code>main.css</code>, but you can call yours whatever you want.</span> <span data-preserver-spaces="true">To link the created CSS file with the Shiny app, we have to add a <code>theme</code> to <code>shiny.fluidPage</code>. Here's how:</span> <pre><code class="language-r">ui &lt;- fluidPage(  theme = "main.css",  tags$ul(    tags$li(a(href = route_link("/"), "Dashboard")),    tags$li(a(href = route_link("settings"), "Settings")),    tags$li(a(href = route_link("contact"), "Contact"))  ),  router$ui )</code></pre> <span data-preserver-spaces="true">The value for the <code>theme</code> parameter must be identical to the name of the CSS file. </span> <span data-preserver-spaces="true">If you were to run the app now, everything would look the same as before. That's because we haven't added any stylings yet. Copy the following code snippet to your CSS file:</span> <pre><code class="language-r">ul {  background-color: #0099f9;    display: flex;  justify-content: flex-end;  list-style-type: none; } <br>ul li a {  color: #ffffff;    display: block;  font-size: 1.6rem;  padding: 1.5rem 1.6rem;  text-decoration: none;  transition: all, 0.1s; } <br>a:link, a:visited, a:hover, a:active {  color: #ffffff;    text-decoration: none; } <br>ul li a:hover {  background-color: #1589d1;    color: #ffffff; }</code></pre> <span data-preserver-spaces="true">Save and rerun the application. You will see the following:</span> <img class="wp-image-6032 size-full" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b021a49bd6df84c7f5c409_002-2.gif" alt="Styled Shiny Router App" width="888" height="282" /> Styled Shiny Router App <span data-preserver-spaces="true">And that's how you can style <code>shiny.router</code> and Shiny apps in general.</span> <h2 id="conclusion"><span data-preserver-spaces="true">Conclusion</span></h2> <span data-preserver-spaces="true">In this short hands-on guide, we've covered the intuition and logic behind the <code>shiny.router</code> package. We've seen how routing works, how to create navigation bars with routing, and how to style navigation bars.</span> <span data-preserver-spaces="true">You can learn more about <code>shiny.router</code> and other Appsilon's open-source packages below:</span> <ul><li><a class="editor-rtfLink" href="https://wordpress.appsilon.com/shiny-router-package/" target="_blank" rel="noopener noreferrer"><span data-preserver-spaces="true">Official Release of shiny.router and its New Features</span></a></li><li><a class="editor-rtfLink" href="https://wordpress.appsilon.com/rapid-internationalization-of-shiny-apps-shiny-i18n-version-0-2/" target="_blank" rel="noopener noreferrer"><span data-preserver-spaces="true">How to Add Multi-Language Support to Shiny Apps</span></a></li><li><a class="editor-rtfLink" href="https://wordpress.appsilon.com/shiny-dashboard-ui-crash-course/" target="_blank" rel="noopener noreferrer"><span data-preserver-spaces="true">Why is My Dashboard Ugly? A Crash Course in R Shiny UI</span></a></li><li><a class="editor-rtfLink" href="https://wordpress.appsilon.com/shiny-worker-package/" target="_blank" rel="noopener noreferrer"><span data-preserver-spaces="true">shiny.worker: Speed Up R Shiny Apps by Offloading Heavy Calculations</span></a></li><li><a class="editor-rtfLink" href="https://wordpress.appsilon.com/r-shiny-faster-updateinput-css-javascript/" target="_blank" rel="noopener noreferrer"><span data-preserver-spaces="true">Make R Shiny Dashboards Faster with updateInput, CSS, and JavaScript</span></a></li></ul> <a href="https://appsilon.com/careers/"><img class="aligncenter wp-image-5940 size-medium" src="https://wordpress.appsilon.com/wp-content/uploads/2020/11/appsilon.hiring0-600x338.jpg" alt="" width="600" height="338" /></a> <p style="text-align: center;"><strong><span data-preserver-spaces="true">Appsilon is hiring! We are primarily seeking a senior-level engineering manager who can mentor our junior developers. See our </span></strong><a class="editor-rtfLink" href="https://wordpress.appsilon.com/careers/" target="_blank" rel="noopener noreferrer"><strong><span data-preserver-spaces="true">Careers</span></strong></a><strong><span data-preserver-spaces="true"> page for all new openings, including openings for a </span></strong><a class="editor-rtfLink" href="https://wordpress.appsilon.com/careers/#project-manager" target="_blank" rel="noopener noreferrer"><strong><span data-preserver-spaces="true">Project Manager</span></strong></a><strong><span data-preserver-spaces="true"> and </span></strong><a class="editor-rtfLink" href="https://wordpress.appsilon.com/careers/#community-manager" target="_blank" rel="noopener noreferrer"><strong><span data-preserver-spaces="true">Community Manager</span></strong></a><strong><span data-preserver-spaces="true">.</span></strong></p>

Have questions or insights?

Engage with experts, share ideas and take your data journey to the next level!

Is Your Software GxP Compliant?

Download a checklist designed for clinical managers in data departments to make sure that software meets requirements for FDA and EMA submissions.
Explore Possibilities

Share Your Data Goals with Us

From advanced analytics to platform development and pharma consulting, we craft solutions tailored to your needs.

Talk to our Experts
shiny
shiny dashboards
open source
r
tutorials