shiny fluent hex

Tutorial: Build a Full Shiny Dashboard With shiny.fluent


shiny.fluent – Taking Shiny Dashboards to New Heights

With Appsilon’s recent public launch of two new R packages – shiny.fluent and shiny.react, the accessibility of React libraries to the Shiny dev community is now easier than ever. shiny.react opens up the rich React ecosystem (e.g., frameworks, blueprints, and components for charts and maps) to R developers, creating the opportunity to improve development speed, app functionality, and design. The ability to port entire React UI libraries is now possible through shiny.react.

For professional, elegant designs consistent with enterprise-grade applications shiny.fluent joins the efficiency of Microsoft’s Fluent UI and R’s advanced data handling capabilities.  With a significant set of components allowing for unique functions like the ‘People Picker‘, ‘Teaching Bubble‘, and ‘Hover Card‘, and support for powerful functions like Stack(), users can be flexible with component placements in the dashboard. Through shiny.react, shiny.fluent makes it possible for the R community to access the power of React JavaScript library and Microsoft’s Fluent UI.

  1. Welcome to shiny.fluent
  2. Getting started
  3. Creating shiny.fluent dashboards
  4. Single Page Layout
  5. Dashboard Layout
  6. Filling All the Areas
  7. Additional Pages
  8. Conclusion

Read More: Why You Should Use Shiny for Enterprise Application Development

Welcome to shiny.fluent

Shiny.fluent ports Fluent UI to R using shiny.react machinery, giving powerful, professional, and user-friendly interfaces to the Shiny community. In this tutorial, we will walk you through how to create a dashboard for a Fluent UI app to improve upon a simple sales analysis application. If you haven’t already, we recommend you start your shiny.fluent adventure here to familiarize yourself with using Fluent components – the tutorial below will build on what you learn there. 

Getting Started

Shiny.react was created with ease-of-use in mind for R developers. Inputs are as close as possible to the Shiny API and the react package(s) documentation is provided inside the R documentation system. To begin use of shiny.fluent we will install the shiny.react and shiny.fluent packages. 

Installation

To install the packages, run:

remotes::install_github("Appsilon/shiny.react")
remotes::install_github("Appsilon/shiny.fluent")

Prerequisites

With shiny.react and shiny.fluent packages installed, let’s load the libraries needed for this example.

library(dplyr)
library(ggplot2)
library(glue)
library(leaflet)
library(plotly)
library(sass)
library(shiny)
library(shiny.fluent)
library(shiny.router)

Creating a shiny.fluent dashboard

In this tutorial, we will walk through how to build a dashboard UI.

Single Page Layout

As a next step, let’s add a title and subtitle to our current app. We’ll create a helper function and call it makePage, so that it is easy to add more pages in the same fashion.

makePage <- function (title, subtitle, contents) {
  tagList(div(
    class = "page-title",
    span(title, class = "ms-fontSize-32 ms-fontWeight-semibold", style =
           "color: #323130"),
    span(subtitle, class = "ms-fontSize-14 ms-fontWeight-regular", style =
           "color: #605E5C; margin: 14px;")
  ),
  contents)
}

We can now take our entire UI built so far and put it in a “page” layout, giving it a helpful title and subtitle.

analysis_page <- makePage(
  "Sales representatives",
  "Best performing reps",
  div(
    Stack(
      horizontal = TRUE,
      tokens = list(childrenGap = 10),
      makeCard("Filters", filters, size = 4, style = "max-height: 320px"),
      makeCard("Deals count", plotlyOutput("plot"), size = 8, style = "max-height: 320px")
    ),
    uiOutput("analysis")
  )
)

ui <- fluentPage(
  tags$style(".card { padding: 28px; margin-bottom: 28px; }"),
  analysis_page
)

 

Dashboard Layout

It’s time to create a place for our header, navigation sidebar, and footer. We’ll use CSS grid for that. It’s a modern, flexible and straightforward way to achieve such a layout.
We start by creating divs for each of the areas, with placeholder texts that we will later replace.

header <- "header"
navigation <- "navigation"
footer <- "footer"

layout <- function(mainUI){
  div(class = "grid-container",
      div(class = "header", header),
      div(class = "sidenav", navigation),
      div(class = "main", mainUI),
      div(class = "footer", footer)
  )
}

Now it’s time to tell the browser using CSS how to arrange these areas. To define how our areas should be laid out on the page, let’s put the following rules in www/style.css:

.grid-container {
  display: grid;
  grid-template-columns: 320px 1fr;
  grid-template-rows: 54px 1fr 45px;
  grid-template-areas: "header header" "sidenav main" "footer footer";
  height: 100vh;
}

.header {
  grid-area: header;
  background-color: #fff;
  padding: 6px 0px 6px 10px;
  display: flex;
}

.main {
  grid-area: main;
  background-color: #faf9f8;
  padding-left: 40px;
  padding-right: 32px;
  max-width: calc(100vw - 400px);
  max-height: calc(100vh - 100px);
  overflow: auto;
}

.footer {
  grid-area: footer;
  background-color: #f3f2f1;
  padding: 12px 20px;
}

.sidenav {
  grid-area: sidenav;
  background-color: #fff;
  padding: 25px;
}

We can also use this opportunity to add some additional styling for the entire page, and add the following rules to the same file:

body {
  background-color: rgba(225, 223, 221, 0.2);
  min-height: 611px;
  margin: 0;
}

.page-title {
  padding: 52px 0px;
}

.card {
  background: #fff;
  padding: 28px;
  margin-bottom: 28px;
  border-radius: 2px;
  background-clip: padding-box;
}

Now we only need to update our UI definition to load styles from www/style.css and use the new layout.

ui <- fluentPage(
  layout(analysis_page),
  tags$head(
    tags$link(href = "style.css", rel = "stylesheet", type = "text/css")
  ))

Sales representative dashboard with empty header, navigation sidebar, and footer created with shiny.fluent

Filling All the Areas

Moving forward, we may now begin adding a Header, Footer, and Sidebar to the empty areas of our dashboard.

Header

Let’s replace the previous header definition with:

header <- tagList(
  img(src = "appsilon-logo.png", class = "logo"),
  div(Text(variant = "xLarge", "Sales Reps Analysis"), class = "title"),
  CommandBar(
    items = list(
      CommandBarItem("New", "Add", subitems = list(
        CommandBarItem("Email message", "Mail", key = "emailMessage", href = "mailto:me@example.com"),
        CommandBarItem("Calendar event", "Calendar", key = "calendarEvent")
      )),
      CommandBarItem("Upload sales plan", "Upload"),
      CommandBarItem("Share analysis", "Share"),
      CommandBarItem("Download report", "Download")
    ),
    farItems = list(
      CommandBarItem("Grid view", "Tiles", iconOnly = TRUE),
      CommandBarItem("Info", "Info", iconOnly = TRUE)
    ),
    style = list(width = "100%")))

As you can see, we’re using CommandBar and CommandBarItem from shiny.fluent. We also need to add a bit of styling to our CSS file:

.title {
  padding: 0px 14px 0px 14px;
  color: #737373;
  margin: 6px 0px 6px 10px;
  border-left: 1px solid darkgray;
  width: 220px;
}

.logo {
  height: 44px;
}

Navigation in the Sidebar

Nav is a very powerful component from Fluent UI. It has very rich configuration options, but we will use it to show just a couple of links:

navigation <- Nav(
  groups = list(
    list(links = list(
      list(name = 'Home', url = '#!/', key = 'home', icon = 'Home'),
      list(name = 'Analysis', url = '#!/other', key = 'analysis', icon = 'AnalyticsReport'),
      list(name = 'shiny.fluent', url = 'http://github.com/Appsilon/shiny.fluent', key = 'repo', icon = 'GitGraph'),
      list(name = 'shiny.react', url = 'http://github.com/Appsilon/shiny.react', key = 'shinyreact', icon = 'GitGraph'),
      list(name = 'Appsilon', url = 'http://appsilon.com', key = 'appsilon', icon = 'WebAppBuilderFragment')
    ))
  ),
  initialSelectedKey = 'home',
  styles = list(
    root = list(
      height = '100%',
      boxSizing = 'border-box',
      overflowY = 'auto'
    )
  )
)

Footer

Footer is relatively straightforward - we can put anything we want there. Here we use Text for typography (setting uniform font styling). We also use Stack to arrange elements horizontally and with bigger gaps.

footer <- Stack(
  horizontal = TRUE,
  horizontalAlign = 'space-between',
  tokens = list(childrenGap = 20),
  Text(variant = "medium", "Built with ❤ by Appsilon", block=TRUE),
  Text(variant = "medium", nowrap = FALSE, "If you'd like to learn more, reach out to us at hello@appsilon.com"),
  Text(variant = "medium", nowrap = FALSE, "All rights reserved.")
)


layout <- function(mainUI){
  div(class = "grid-container",
      div(class = "header", header),
      div(class = "sidenav", navigation),
      div(class = "main", mainUI),
      div(class = "footer", footer)
  )
}

# ---
ui <- fluentPage(
  layout(analysis_page),
  tags$head(
    tags$link(href = "style.css", rel = "stylesheet", type = "text/css")
  ))

Let’s see how this looks together.

Sales representative dashboard with filled header, navigation sidebar, and footer created with shiny.fluent

Additional Pages

The final step is to add pages and enable navigation between them.

Home Page

Let’s make a home page, consisting of two cards with some welcome text.

card1 <- makeCard(
  "Welcome to shiny.fluent demo!",
  div(
    Text("shiny.fluent is a package that allows you to build Shiny apps using Microsoft's Fluent UI."),
    Text("Use the menu on the left to explore live demos of all available components.")
  ))

card2 <- makeCard(
  "shiny.react makes it easy to use React libraries in Shiny apps.",
  div(
    Text("To make a React library convenient to use from Shiny, we need to write an R package that wraps it - for example, a shiny.fluent package for Microsoft's Fluent UI, or shiny.blueprint for Palantir's Blueprint.js."),
    Text("Communication and other issues in integrating Shiny and React are solved and standardized in shiny.react package."),
    Text("shiny.react strives to do as much as possible automatically, but there's no free lunch here, so in all cases except trivial ones you'll need to do some amount of manual work. The more work you put into a wrapper package, the less work your users will have to do while using it.")
  ))

home_page <- makePage(
  "This is a Fluent UI app built in Shiny",
  "shiny.react + Fluent UI = shiny.fluent",
  div(card1, card2)
)

If we replace analysis_page with home_page in our UI, we can see this page. However, there’s one problem: we don’t have a way to switch between pages! This is where so-called page routing comes into play.

Adding shiny.router

To enable switching between pages we will use the shiny.router package. This way we will also have shareable URLs to individual pages.

The first step is to define the available routes:

router <- make_router(
  route("/", home_page),
  route("other", analysis_page))

Now, we need to put router$ui in the place where we want the selected page to appear. (Currently, we also need to manually include router’s JavaScript dependencies, because shiny.fluent is not compatible with the way shiny.router loads this dependency. We expect this to be resolved in future versions of shiny.router).

# Add shiny.router dependencies manually: they are not picked up because they're added in a non-standard way.
shiny::addResourcePath("shiny.router", system.file("www", package = "shiny.router"))
shiny_router_js_src <- file.path("shiny.router", "shiny.router.js")
shiny_router_script_tag <- shiny::tags$script(type = "text/javascript", src = shiny_router_js_src)


ui <- fluentPage(
  layout(router$ui),
  tags$head(
    tags$link(href = "style.css", rel = "stylesheet", type = "text/css"),
    shiny_router_script_tag
  ))

One final step is to add this single line to our server function, which otherwise remains untouched from the Part 1 of the tutorial.

router$server(input, output, session)

That's it!

And there you go! We now have styled a shiny.fluent app into a solid dashboard layout. Here’s the final result:

Completed Fluent UI app using shiny.fluent with additional pages and routing options using shiny.router

Conclusion

The speed at which you can now add user-friendly and ubiquitous Microsoft product elements to your project is quite impressive. In a matter of minutes, we were able to create a functional, professional-looking Shiny dashboard with shiny.fluent. And if your users are already familiar with Microsoft products, adoption can be seamless. 

There is more complexity over something like shiny.semantic. However, an intermediate level of knowledge of Shiny is sufficient to begin. Component examples are provided and more comprehensive documentation can be found in the official Fluent UI docs or by typing shiny.fluent::  (e.g., ‘?shiny.fluent::MyComponentName’).

Please feel free to post any comments regarding shiny.fluent on our feedback thread. We love to hear feedback from our users and are happy to help should you have questions. If you like the package and want to show your support, please consider dropping a star on the shiny.fluent package at our Github and browse our other shiny packages

Appsilon is Hiring

If you’re interested in contributing to groundbreaking projects and working with leading experts in Shiny, consider joining our team. Appsilon is a global, remote-first company meaning we have team members working across the globe (7+ countries!). We are looking for talented individuals to help us in achieving our core purpose:

Advance technology to preserve and improve human life #purpose 

We are motivated by ethical goals and impactful projects (like our open source projects and #AI4Good). Appsilon actively promotes and seeks to be a welcoming and diverse workplace. See how we achieve this by creating an inclusive work environment.

Be a part of our team

Appsilon is hiring for remote roles! See our Careers page for all open positions, including a React Developer and R Shiny Developers. Join Appsilon and work on groundbreaking projects with the world’s most influential Fortune 500 companies.