Combining glide.js and R shiny
Sometimes when building a shiny
app, more visually appealing tools are necessary. It makes your app to look better but also can improve its usability. Carousels are useful when the desire is to display several images/HTML, giving freedom to the user to browsers among the content. In this post, I will show how to use glide.js together with your shiny
app.
The glide.js
library is JavaScript
framework that provides several options to customize carousels. It is a powerful tool with several options to customize your carousel. A nice aspect about glide.js
is that you can build your carousel using only a few lines of code without any complication. Also, no installation is needed since CDN services are available
Top 10 ATP players
To illustrate the glide.js
usage, I collected some images from the ATP website. More precisely, I collected the photos and country flags of the top 10 players on the current date (05/11/2022). In a new R file, paste the following code which I will use later:
library(shiny)
content <- list(
list(
src = "https://www.atptour.com/-/media/tennis/players/gladiator/2022/05/25/15/16/alcaraz-full-2022-may.png",
background = "https://www.atptour.com/-/media/tennis/players/profile-hero/alcaraz-player-profile-banner-december-2021.jpg",
name = "Carlos Alcaraz",
rank = "#1"
),
list(
src = "https://www.atptour.com/-/media/tennis/players/gladiator/2022/05/25/15/07/nadal-full-2022-may.png",
background = "https://www.atptour.com/-/media/tennis/players/profile-hero/heritage-player/nadal-no1-playerbg-2022-pepperstone.jpg",
name = "Rafael Nadal",
rank = "#2"
),
list(
src = "https://www.atptour.com/-/media/tennis/players/gladiator/2022/05/18/21/12/medvedev-full-2022-may.png",
background = "https://www.atptour.com/-/media/tennis/players/profile-hero/medvedev-player-profile-banner-march-2022.jpg",
name = "Daniil Medvedev",
rank = "#3"
),
list(
src = "https://www.atptour.com/-/media/tennis/players/gladiator/2022/06/07/13/21/ruud-full-2022-may.png",
background = "https://www.atptour.com/-/media/tennis/players/profile-hero/by-country/nor.jpg",
name = "Casper Ruud",
rank = "#4"
),
list(
src = "https://www.atptour.com/-/media/tennis/players/gladiator/2022/05/18/21/10/tsitsipas-full-2022-may.png",
background = "https://www.atptour.com/-/media/tennis/players/profile-hero/tsitsipas-player-profile-banner-december-2021.jpg",
name = "Stefanos Tsitsipas",
rank = "#5"
),
list(
src = "https://www.atptour.com/-/media/tennis/players/gladiator/2022/06/27/05/08/zverev-full-2022-june-final.png",
background = "https://www.atptour.com/-/media/tennis/players/profile-hero/zverev-player-profile-banner-july-2022.jpg",
name = "Alexander Zverev",
rank = "#6"
),
list(
src = "https://www.atptour.com/-/media/tennis/players/gladiator/2019/02/25/18/13/djokovic_full_ao19.png",
background = "https://www.atptour.com/-/media/tennis/players/profile-hero/heritage-player/djokovic-no1-playerbg-2022-pepperstone.jpg",
name = "Novak Djokovic",
rank = "#7"
),
list(
src = "https://www.atptour.com/-/media/tennis/players/gladiator/2022/05/25/15/13/auger-aliassime-full-2022-may.png",
background = "https://www.atptour.com/-/media/tennis/players/profile-hero/by-country/can.jpg",
name = "Felix Auger-Aliassime",
rank = "#8"
),
list(
src = "https://www.atptour.com/-/media/tennis/players/gladiator/2022/06/27/05/08/rublev-full-2022-june-final.png",
background = "https://www.atptour.com/-/media/tennis/players/profile-hero/by-country/rus.jpg",
name = "Andrey Rublev",
rank = "#9"
),
list(
src = "https://www.atptour.com/-/media/tennis/players/gladiator/2022/06/27/05/08/hurkacz-full-2022-june-final.png",
background = "https://www.atptour.com/-/media/tennis/players/profile-hero/by-country/pol.jpg",
name = "Hubert Hurkacz",
rank = "10"
)
)
Also, let’s create a function to generate a simple card that will be used later in our carousel. Basically, the function is creating a div
tag containing the player’s photo with a flag at the background as well as adding the player’s name and ranking:
make_card <- function(x) {
tags$div(
style = "width: auto",
tags$img(
src = x$src,
style = sprintf("background-image: url(%s)", x$background)
),
tags$h3(
sprintf("%s - %s", x$name, x$rank),
class = "names"
)
)
}
html_cards <- lapply(X = content, FUN = make_card)
In a new css
file, save the following style for the names
class as well as the app title style:
.app-title {
margin: 50px 10px;
}
.names {
width: fit-content;
font-size: 24px;
margin: 2%;
padding: 10px;
color: #ffffff;
background: #3a3a3a;
border-radius: 10px;
}
Right now, we are already able to create a shiny app with the desired content. In the R file, let’s create a simple shiny app:
# simple ui
ui <- fluidPage(
# css and js
includeCSS(path = "path/to/your/file.css"),
# ui
tags$h1("Top 10 ATP players on November 5th, 2022", class = "app-title"),
html_cards
)
server <- function(input, output) {}
shinyApp(ui = ui, server = server)
The result should be a fluid page with the cards below each other. Using the page scroll you are able to see all 10 players. However, that is not the best way to present this content. Let’s see what we can do using the glide.js
library.
Creating a carousel using glide.js
In order to use the glide.js
library, we need to include its js
functions as well as the css
code. It can be done easily using the CDN service. At the very beginning of your shiny app, include the glide.js
source code as below:
ui <- fluidPage(
# glidejs
tags$link(rel = "stylesheet", href = "https://cdnjs.cloudflare.com/ajax/libs/Glide.js/3.0.2/css/glide.core.css"),
tags$script(src = "https://cdn.jsdelivr.net/npm/@glidejs/glide"),
# css and js
includeCSS(path = "path/to/your/file.css"),
# ui
tags$h1("Top 10 ATP players on November 5th, 2022", class = "app-title"),
html_cards
)
I also need to change our content in order to connect it with the glide.js
code. A js
file is needed to initialize the glide.js
carousel class. The following code is creating a glide object using glide.js
library. It is done based on an object of the class glide-grid
(which we will create later in our application). In the following code, we are informing the type of object we want (carousel
) as well as the number of cards we want to see at the same time (perView: 4
).
$(document).ready(function () {
var glideObj = new Glide('.glide-grid', {
type: 'carousel',
perView: 4
});
glideObj.mount();
})
Now, let’s wrap our content in a div that will be used by the glide.js
library. Here, the class we linked in the js file must appear (glide-grid
) so then glide.js
knows where to add the carousel.
ui <- fluidPage(
# glidejs
tags$link(rel = "stylesheet", href = "https://cdnjs.cloudflare.com/ajax/libs/Glide.js/3.0.2/css/glide.core.css"),
tags$script(src = "https://cdn.jsdelivr.net/npm/@glidejs/glide"),
# css and js
includeCSS(path = "path/to/your/file.css"),
includeScript(path = "path/to/your/file.js"),
# ui
tags$h1("Top 10 ATP players on November 5th, 2022", class = "app-title"),
tags$div(
class = "glide glide-grid", # glide-grid class is HERE!
tags$div(
`class` = "glide__track",
`data-glide-el` = "track",
tags$ul(
class = "glide__slides",
html_cards
)
)
)
)
Also, add this new class to your css
file for some simple customization:
.glide-grid {
width: 90%;
margin: 10px auto;
background-color: #efefef73;
border-radius: 15px;
box-shadow: 0 1px 3px 0 #bcbdbd, 0 0 0 1px #d4d4d5;
}
That is all. We already have a carousel!
Of course, we can keep improving our visualizations. For example, we can add controls (since right know it works only by interacting with the mouse). To do so, let’s use the following code and respective css
:
arrow_btn <- function(dir = "<") {
html_code <- tags$div(
`class` = "glide__arrows",
`data-glide-el` = "controls",
tags$button(
`class` = "glide__arrow glide__arrow--left glide-control",
`data-glide-dir` = dir,
dir
)
)
return(html_code)
}
ui <- fluidPage(
# glidejs
tags$link(rel = "stylesheet", href = "https://cdnjs.cloudflare.com/ajax/libs/Glide.js/3.0.2/css/glide.core.css"),
tags$script(src = "https://cdn.jsdelivr.net/npm/@glidejs/glide"),
# css and js
includeCSS(path = "path/to/your/file.css"),
includeScript(path = "path/to/your/file.js"),
# ui
tags$h1("Top 10 ATP players on November 5th, 2022", class = "app-title"),
tags$div(
class = "glide glide-grid",
tags$div(
class = "glide-controls",
arrow_btn(dir = "<"),
arrow_btn(dir = ">")
),
tags$div(
`class` = "glide__track",
`data-glide-el` = "track",
tags$ul(
class = "glide__slides",
html_cards
)
)
)
)
.glide-controls {
padding: 5px;
display: flex;
}
.glide-control {
background: #d3d3d3;
color: white;
border: solid 1px white;
border-radius: 5px;
}
If you are interested, the library still provides several ways to customize the interaction with the carousel. Have a look at glide.js
options.
Conclusion
The glide.js
library is powerful and simple to use. With a few lines of code, it is possible to create a carousel and easily embed it in shiny.
This post is intended to present the basic idea of how to use glide.js
together with R and then just a few functions were explored.