
Next Generation Shiny Apps with {bslib}
In this workshop, led by Garrick Aden-Buie, a software engineer for Shiny at Posit, you will learn how to build Shiny apps using modern user interfaces and layouts with bslib, the next generation of Shiny UI. Garrick will guide you through creating stylish and convenient dashboard layouts and components, demonstrating how bslib can effectively replace shinydashboard. Additionally, you will explore innovative techniques for deploying Shiny apps using shinylive, enabling the creation of static sites that run entirely in the user’s browser without the need for a Shiny server. Main Sections 00:00 Introduction 11:00 Shiny 14:57 How bslib started 18:29 Theming from start to advanced 22:19 College Scorecard Data 39:24 bslib layouts 01:20:25 Advanced layouts 01:49:18 Filling Layouts 02:42:09 Details on demand 02:50:01 New inputs 02:53:15 Wrap up More resources R Validation Hub Site: https://www.pharmar.org/ Main Site: https://www.r-consortium.org/ News: https://www.r-consortium.org/news Blog: https://www.r-consortium.org/news/blog Join: https://www.r-consortium.org/about/join Twitter: https://twitter.com/rconsortium?lang=en LinkedIn: https://www.linkedin.com/company/r-consortium Mastodon: https://fosstodon.org/@RConsortium
image: thumbnail.jpg
Transcript#
This transcript was generated automatically and may contain errors.
Okay, well it's about almost five after and it seems like everybody's here who wants to be here, so let's get started. I'm going to paste these links again, post that one more time in case you missed it the first time I posted. There's a website for this workshop and it's probably a good idea to just open that up and find it and have it open in a tab. And there's only really two sections of the website. There's the home page here which gives you a little intro to what we're going to be doing today and also a reminder that this is the Next Generation Shiny Apps with bslib workshop at R Medicine, so hopefully you're in the right place. And this intro page will walk you through getting set up and there'll be a little bit of time where you can kind of do that or you can do that in the background while I'm kind of introducing everything for the workshop.
And then there's also a page that says workshop with kind of a list of the things that I'm hoping or expecting or planning to cover today. I'm just going to go right to the welcome get getting started and I'll open this up and open up these slides so we can talk. So hello and welcome everyone. Like I said this is the Next Generation Shiny Apps with bslib.
And I'm Garrick, Garrick Adenbuie. You can find me online at garrickadenbuie.com or on Mastodon, those kinds of places. But in day-to-day I work for Posit on the Shiny team. I joined Shiny about a year and a half ago more or less and most of my time in the past, at least in the first year on the Shiny team, was working with bslib.
And I noticed that I might have frozen.
Am I back? Did I freeze for a second? I can't tell if that was... I was hearing you fine the whole time. Okay. Did my camera freeze? Not on my end. Okay. All right. All right. Thank you Zoom for that little wrinkle. But thank you. I'm glad that you're here to confirm that. Okay. So yeah. So I've been working with Shiny, bslib, right? This is, which is the package we're going to be talking about. And I've been working mostly I've been working mostly in bslib for the last year. So I'm excited to share some of the things that we've been working on, some of the vision that we have for the package in general, and how it fits into the Shiny ecosystem and into the future of Shiny.
Workshop overview and logistics
So before we get started, just a couple quick little things about the workshop to set sort of expectations for what we're gonna be doing today. We're planning on this being about three hours until 2 p.m. Eastern. I would like to use breakout groups for exercises. And we'll talk about the setup for that in a little bit. Please feel free to turn your video on if you want to, or unmute yourself if you have a question. It is helpful to see your faces. At the same time, I understand that you might not be in a place where video is easier appropriate.
So I'll also, I have the chat window open as well. You are welcome to use chat at any time. Just drop a question in there. Or you can use the raise your hand feature of Zoom. If you use chat and you write a question in the chat, if you would like, if you for some reason would like me to not, or sorry, let me back that up. So if you have a question in chat, I might call on you to read your question out loud so we can talk about it. If you would prefer that I just read your question for you, please put a star at the start of the question and I'll just read it and no worries. Zoom has this cool little feature called raising hands, I guess, where if you find the bar at the bottom of the Zoom window, there's the reactions tab. You click on that and then there's a raise hand button there. And I'm pretty sure that floats you to the top of my participants list and I'll be able to see that and call on you. And you would use that method if you want to either use voice or video. So feel free to use that feature.
There is a code of conduct for the workshop and for R-minus and in general. Please behave professionally. And that's pretty much it. If anybody, if there's any kind of issue that happens today, I really hope that there isn't. But if there is, you can reach out to me with a private chat or to Emily, who is also the host on this meeting, or reach out to me during the breakout sessions.
Breakout session format
So how do I envision these breakout sessions working? There's a lovely concept called pair programming, which is something that I really enjoy, which is basically working together with other people on writing code. And I'm hoping we can kind of use that as a model for the breakout sessions. We have about, I'm imagining we'll use about five people per breakout group or something like that, four or five people per breakout group.
And when you move into a breakout session, the model for pair programming is basically that one person drives, like one person is the person who actually writes the code. And in this case, if one person could volunteer themselves to share their screen during the session, that would be extremely helpful. And that way, not everyone needs to share their screen, but we can all still work together. The role of the other people, usually pair programming is two people, but this is somewhere between pair programming and mob programming. But the role of the person who is not driving, as in not actually typing the code into the screen or clicking the mouse around, is to help out, to watch what the person who is driving is doing, review their code, give them some guidance, say, hey, oops, you missed a comma or parentheses here or there, or maybe go look something up in the documentation. And hopefully together, working together, the exercises will be kind of smooth sailing, but a fun way to practice what we talk about today during our sessions.
What is bslib?
Okay. So let's actually get into talking about this. So what is bslib? Well, first of all, first back in, you know, first there was this package called Shiny. And actually not really, because before Shiny, there was this package, this web framework called bslib. So we have to go back just a little bit more. When Shiny came around, Shiny used this Bootstrap web framework as a way to lay out the UI elements and to make web apps that look actually pretty good. And Bootstrap was actually created by a couple of engineers at Twitter. And it was released in 2011. And at the time, it was like one of the first web frameworks. I mean, there have been lots of web frameworks in the history of the web. But this was one of the first that was just like a really nice combination of CSS, which is how new web pages are styled, and a bunch of HTML kind of templates that were easy to use. And it just, it just took the web by storm. And pretty soon, everybody was using Bootstrap to style their websites.
And when Joe built Shiny in 2012, and released it, he used Bootstrap as a quick way to, you know, to make sure or to just make apps that look really nice. So it was a, it was a win for everybody. In 2013, so two years later, Bootstrap, I think, you know, when we when Shiny started using Bootstrap, it was on version two. And then in 2013, Bootstrap released version three, which was a complete rewrite of Bootstrap. And they have a tendency to do this every, you know, three to five years. And, and then Shiny in 2014, moved to using Bootstrap three. So, so Shiny has a pretty, you know, a pretty tight history with Bootstrap. And Bootstrap, it's is pretty integrated into, into Shiny.
Yeah, and I'm realizing now that, you know, I'm assuming most of everyone here is aware of what Shiny is and what it does in our world. But if you are not, then, you know, or if you want me to, like, talk a little bit more about the background of, of like, what Shiny is, or what it does, you can drop me a note. And I will, I will backtrack just a little bit.
Okay, but in 2014, the Shiny engineers, at the time, mostly Winston and Joe, made a big push to move Shiny from Bootstrap two to Bootstrap three. And since then, Shiny is still using, for the most part, Bootstrap three. And this is sort of a feature and a bug at the same time. It's on the one hand, it's really nice that Shiny has been so stable over so many years. And on the other hand, it would be really nice to have some more modern UI styling and elements, right?
Shiny's UI and Bootstrap
So let's, let's take a look at, like, fundamentally what Shiny does and how it works. And this workshop is where you're focusing almost entirely on front-end code. So in a Shiny app, you have two pieces, you have a UI side, which is how you define, like, what shows up in the app and what people see when they come to use your, your Shiny app. And, and then there's a server side. And on the server side is where you kind of do all of, write all of the R code that is really about the logic of how data flows through your app, and you know, what happens when you change an input and that kind of thing. And so the apps that we see today are going to involve a lot of server code that we are just not going to talk about at all. We're going to focus almost entirely on front-end code.
So what happens in the front end? What happens in the UI of a Shiny app? You know, the server part is, is really, really awesome, but also the part where you can write, where Shiny lets you write R functions, and you don't have to think about web stuff at all. You can just think about here, I have a numeric input and I've given it an ID so that I can use that on the server side. It has a label that I know, you know, will show up in the, and, you know, tell people what this input is about. And I'm going to set it to an initial value, give it a min and max range. And when, and what Shiny does is basically takes this idea of a numeric input that I have, you know, specified in R code, and it turns it into basically raw HTML. Like if you wanted to make this, if you wanted to make a web page on your own, you would have to write all of these things. There's a lot of extra stuff in here, like there's divs and labels and inputs, and, and some people find that fun to write all of this, and some people, you know, prefer to just think about the, the stuff that just matters for the thing that you're trying, the input that you're trying to create.
And if we took this just basic raw HTML and we put it into the browser, it would look like this. It would, you know, here's the label, our academic year start is here in the label element, which shows up here. And then we have, we have an input where the value in here is going to be a number, and you can move it up and down by one, and it started at 2012, right? Okay. That's the extent of what happens with this code. This doesn't actually like connect to a server or anything. I'm only moving, like, this isn't connected to anything. It just, first of all, it's not connected to anything. And then second of all, it looks pretty basic.
So what Bootstrap does is it takes the, takes the same HTML, this, you know, the same basic structure of the HTML, but now it has, we've sprinkled in just a couple classes. So we've got the form group class, we've got control label class here, we've got another class on the input element. And now that we have these classes with Bootstrap, our input looks quite a bit different. And it's definitely more stylish, and it's more what we have come to expect when we go to a website and see an input like this, right? So that's the role of Bootstrap, is to go from, to take this kind of HTML, and that looks kind of boring, and turn it into something that looks better, right?
Introducing bslib theming
And over the years, the sort of styles of Bootstrap have evolved somewhat, but they're still pretty similar. So here's what Bootstrap 3 looks like, which we were just looking at. And here's what Bootstrap 5 looks like, the most recent version of Bootstrap. It's a little bit, you know, it's pretty similar, but also a little bit different, right? Okay, so bslib, where does bslib enter into this? So I think, you know, we kind of learned from the experience of moving from Bootstrap 2 to Bootstrap 3, that Shiny is very tightly integrated with the HTML markup that we create. So, you know, there are a lot of assumptions that we make about what that HTML is going to look like, and how we're going to interact with it, that's going to, like, power all of the server side of things. So for, so bslib kind of came into this thinking, you know, Bootstrap is coming out with version 4 and version 5. And how do we bring those into Shiny, rather than rewriting everything that's inside of Shiny, when we want to upgrade from one Bootstrap version to another.
And so that was the first kind of task of bslib. And then the second task of bslib is also, like, let's make it possible to do theming and to change the appearance of a Shiny app easily and quickly without doing a whole lot of extra work. And so this is what bslib started doing. So you, the idea with bslib was that you could take bslib, and it gives you a theme, a BS theme function that you pass to a theme argument of one of the page functions in Shiny. And here you could say version 5, right, so I want Bootstrap version 5, and do nothing to the rest of your app, and your app would just automatically be using Bootstrap 5 and look much better.
So here's what, you know, what that would look like with version 5. And so then the other part of this, you know, that part's cool. So now we've, like, upgraded to version 5. This is a Shiny, this is a Shiny input now on version 5, on Bootstrap version 5. But then also to make theming more accessible and more fun, we need, we added this idea of presets. So the nomenclature has changed a little bit over the years. We, Bootstrap's theme originally was just about bringing in also boot swatch themes. Boot swatch is like a collection of pre-built preset Bootstrap themes. And recently we've added our own to that collection. So we had to move away from just calling this argument boot swatch. So a preset is like a Bootstrap theme preset that's sort of ready to go. You can leave it like that and get a new theme for your Shiny app, or you could, you could build on top of it and make some changes. So here is the Darkly boot swatch preset. You know, you change one argument and the next thing you know you have a brand new, brand new looking app.
change one argument and the next thing you know you have a brand new, brand new looking app.
And then here recently, like in the last, within the last year we started working on a Shiny specific preset. So you can see this is a little bit different from the stock Bootstrap 5. There's a like higher contrast and on the, on the input and a couple other things, a font that Posit likes and that sort of thing. And so now if you use BS theme without these arguments, this is the default that you'll get. You'll get version 5 with preset Shiny.
So within BS theme, basically if you're using BS theme, you're going to set a, choose a preset. Then you also can set Bootstrap variables. They're, throughout the Bootstrap documents, there are mentions of these Sass variables that they use, and you can change them directly from BS theme. So here, for example, I'm saying I want primary to be a specific color. And so primary is like the accent color for, for like action buttons and things like that. And success, I want to be this other color. These are roughly like, I think blue and green for those who don't, can't translate hex in their heads like me.
No, I just happen to know that that's what they are. And then you can also enter, you know, grab fonts from Google. So here, these last two lines are saying, I want to use enter from Google fonts for the base font. And I want to use JetBrains mono for the code font. And, and, you know, just like that, you rebuild Bootstrap's Sass into CSS, you get a whole new Bootstrap theme.
And, and it's pretty neat. So if, if you're interested, if like, if you're really interested in this part of bslib, this is probably, we'll do a little exercise now on that, where you get to practice using these things. But beyond that, the, you know, we won't, the rest of the workshop is gonna be mostly talking about the other new, newer things that bslib has added. But a good introduction to theming is the Get Started theming article. And if you're wondering how you find these kinds of, these kinds of Sass variables that I mentioned that you can change in a theme, you, we have a page in, in the bslib docs, where under theming, you can go to theming variables. And here you can see like a whole list of these things. Fortunately, there's a search. So if you're interested in like, finding things that are related to primary, for example, you can find them, you know, or like, if you want to search for fonts, this is a good way to, to look at what variables are available as for a first specific kind of thing.
Page functions and the exercise
Okay, so, so with this theming aspect of bslib, we started to realize that sometimes that if all you really want to do is switch from a fluid page with bootstrap version five to, sorry, if you want to switch from fluid page with the bootstrap version of three to a fluid page with the bootstrap version of five, maybe we could make that a little bit easier. And so we started adding functions to bslib that would do that kind of thing. So you can simply replace page, you can replace fluid page with page fluid and, and the rest of your app basically works the same exact way, except now you have the latest version of bootstrap and the latest shiny preset theme from bslib. You can still use everything else that's in shiny inside of your app and you don't have to change anything, but page fluid basically just, you know, gets you the newest bootstrap versions and everything.
Okay, so now it's your turn. I'm going to copy these, paste those links again. Okay, because I noticed some people have joined while I was talking. So in this workshop, we're going to use a data set that I've collected from the Department of Education in the United States. It's called the college scorecard data. It includes data about college enrollment, student aid costs, student outcomes from academic years 1996 through 2022.
And there are basically two tables there. One, the first table is called school, and it gives you some information about each college in the data set. And then there's another table called scorecard, which gives you historical data on the cost of the school, the enrollment outcomes. The scorecard is by academic year, and school is one row per college.
There's a, in the PositCloud project, you'll find a, you'll find a, there's a package that's already installed called college scorecard, and loading that package with library college scorecard brings in these two tables. So they're ready to use as soon as you do that.
So in this next section, we're going to, your job is to find the exercises folder. All of our exercises for today are there. And there's an app called zero one app. There's also a solution there. Don't go look at the solution. Try it without looking at the solution. But if you get stuck, you can go look at the solution and see what's happening and maybe get yourself unstuck. The goal of this exercise is mostly just to make sure that everybody's set up and ready to go. And the task is to take the shiny app that's there and make it bslib-ier by switching out the page function, maybe looking around to see what other page types are available. Try out a new bootstrap or bootswatch theme, and then use the app to learn a little bit about the school data set to kind of get a little bit of a feeling for the school data set.
So I'm going to figure out how to send everyone to breakout sessions. While I do that, I'm going to go back to the website very quickly. And on the homepage, I just want to make sure that you've seen this. If you are wanting to just get set up very, very quickly, on the homepage, you go to using Posit Cloud and follow the instructions. You can sign up for a free account for Posit Cloud and then join the R Medicine 2024 bslib space. And once you're there, there's a project. It's an assignment, which means that when you click on it, it just automatically creates a copy for you that becomes yours to use for the rest of the workshop. I'm going to leave this up while I figure out how to send everyone into breakout groups. And when we're in the breakout groups, we will have, yeah, I'll send like a one minute warning when it's time to come back.
All right. Welcome back. I hope that went well. Would anybody like to report how things went in their breakup group? Were there any troubles getting set up? Did anybody find my typo in the apps?
Feel free to just go ahead and unmute if you want, and if anyone wants to give a small little update.
Well, I can say all we did was just change to page fluid. That's as far as we got.
But it worked, right? Right. Then we tried to figure out how to get a different theme in there, because you showed that, but I forgot what the syntax was.
Yeah. So you did something like... Let me make this bigger. Sorry. We probably did something like this. Yeah, right there. Preset. I was trying to remember how to do the preset.
Yeah. You can also use boot swatch still. So that's still around if you remember that better. And yeah, that works. Or you can call it a preset, which is the sort of newer term.
Exploring the dataset
So anyone else with questions about... Did anyone learn anything about the dataset from this? Maybe we'll do that together real quick.
So this app was kind of designed... Let me go back to my favorite preset, which is the shiny preset. So this app is basically kind of walking through the school table. And the school table has a bunch of different variables like state. So there are the states you would expect, plus a few that you might not. The predominant degree of the school or college. The highest degree, bachelor, graduate, associate certificate of the school or college.
fringe-rural, or remote-rural. Then there are a bunch of, let's see, these are all flags that are like, basically, is it, for example, historically, a black college or university? Is it a tribal university? Etc. Is it only for women? Only for men? Is it distance education only? Most of these are generally false for most schools except for a couple. Oh, and then whether or not tests are required. Cool. And then the scorecard data is going to give you these things. These variables come from the scorecard data where they tell you the number of students by academic year. So in most cases, we're going to just filter to the most recent academic year for a school. And yearly cost is similarly an average cost to attend the school, again, by academic year. So these are some of the variables we're going to be playing around with. And hopefully by the end, I don't know, we'll learn something about colleges in the United States.
Customizing the Shiny app snippet
Okay, so, oh, I did have one more thing to show you before we move on to the next little bit, which is I recently wrote a little blog post. I'll share the link here if you want to just open that and read it later. But when you are making a Shiny app, and I'm going to just copy this to make sure I have it, and then I'll move back to RStudio. So when you are making a Shiny app, you know, you can create a new Shiny app by going through this new R script kind of menu, click on Shiny web app, or sometimes you can just like create a new R file, right? And I don't know if you've ever seen these, when you start typing Shiny, there are these snippets. And for example, you can type Shiny app, and then let me make sure I can trigger it. And then usually when that tab completion is up, I press tab, and then I get like the skeleton for Shiny app.
And recently, I've found this to be kind of limiting because it doesn't include bslib. And if I'm making a small skeleton of a Shiny app, I want it to include bslib. So I'm going to show you how to fix that right now. Under tools, if you go to edit code snippets, it brings up this configuration page. And here are a list of like all of the snippets that you can use. But here's our Shiny app snippet. And then I'm just going to add library bslib here, I'm going to change this to page. And then I'm going to use a new syntax here, which is you can kind of see it, see these up here where I'm going to say one, which means that this is the first sort of thing that can be replaced in the snippet. And I'll put in a default value here. So whichever bslib page function you like the most, you can put this here, but we just were looking at page fluid. So I'll put fluid here. And then, and then that's it. So I'll save this. And if I delete all these things, and I go Shiny app, now my Shiny app snippet is a little bit a little bit different. Now it includes bslib. And it includes the page function. And because I use that special dollar one syntax, it stops first here at page fluid. So I have a default value of page fluid. But you know, if I wanted to, for example, have another page here, like page sidebar, I could just start typing page sidebar. And when I press tab again, it'll bring me into the into the app. And then here I can, you know, put my app things right and just move on from there.
So this, this saves me untold seconds on a daily basis. And it might work for you too. So maybe you'd like that. So just you can save that blog post and walk through that later.
So this, this saves me untold seconds on a daily basis. And it might work for you too.
bslib layout functions
All right. So now that we're up and running, let's talk about some of these layouts that we have in in bslib. I'm going to try this and hope that it works. So I have a, I have shiny, this is a shinylive app running in in the website. You could you could use this too, if you want to, to like, type a log, or for this part, you could just watch too, if you want. So we've seen page fluid. Right, I'm going to, I have a little package called lorem ipsum that I like to use when I'm making like these sort of example UIs. And here, I'm going to just add and whenever you use the so the first argument is the number of paragraphs. And the second argument is the number of sentences in each paragraph. So here I made like two paragraphs of just placeholder text. And so you can kind of get a sense for what happens with page fluid. So page fluid is just like fluid page where it stretches to the full width of whatever viewport you have. There's also page fixed. So that is the same as page as fixed page in shiny. And this is it now has a little bit of a border. I think that's basically the only thing is that like, it doesn't go full width at at certain screen sizes, like here, you can see it's limited to the sort of the center of the screen. That's basically the only difference between page fixed and page fluid.
Okay, and then we have a new function called page sidebar. And page sidebar is going to let me make this slightly bigger. Okay, so page sidebar, basically, you know, has a main content area on the right, and then it adds a sidebar to the left. And there's nothing in this sidebar because I didn't put anything in the sidebar yet. So to put something in the sidebar, you can use the sidebar argument, and then the sidebar function. So you pass the sidebar to sidebar. And here you can put, you know, whatever you want. So, like a numeric input, value, let's see, I'm just going to say n. Let's make this really easy. And now we have, you know, an input in the sidebar. So this is a great place to tuck away inputs that you want to be accessible and you want them to be, you know, available to the user, but also if you want to let the user kind of like hide them and just focus on whatever it is that's in your main content area. Like, you know, like focusing on a plot or something like that. But you have this sort of drawer sidebar of inputs that you can work with.
So page sidebar also takes a title. My first sidebar app. Okay. So it takes a title. And if you give, so if you give it a title, it sort of creates this kind of reminiscent of a nav bar kind of feel. So you have a nice, so this is a really good layout for a dashboard where you have one page on the dashboard. You know, you just have, you know, this page here where there's maybe, you know, one, one, two, three, maybe four plots, but there's, there's only one page to the dashboard. So this is a good, a good fit for that kind of app.
We also now have, well, yeah, so the, so title, you could also give title to sidebar. Like you can maybe call this sidebar settings. And if you give a title to the sidebar, there's a, we add a title here to the top of the app or to the top of the sidebar. So most of the time, and at least in the apps we'll see today, I just sort of leave that off. Let's see, there's a few other arguments here. So if you want to customize the sidebar area, you can, you can do that. You could do something like say, I want my background to be red. This is going to be a bit bright, but it'll still work. And you could make your foreground white. And so, you know, using these settings from the, from the sidebar, you can, you can change sort of the appearance. You can also decide what side it appears on. So you can say position equals right to move it over to the right side of the app. And now it's over here on the right instead of being on the left. And you can also choose whether or not you want it to be open or closed. So we'll say closed as at start. So this argument, just the open argument just decides whether or not it's open or closed at the time when the app loads. But the user might, you know, open it or close it themselves. So it's not going to stay closed permanently. If you want it to stay open, for always and always, you can say open as always. And then, then there's no way that you can collapse this sidebar. So you're kind of, you're stuck with it. And it's, but it's at least there all the time.
Cards and layout columns
So, so let's see, this is a page sidebar with the sidebar, as we talked about. So we also have a bunch of components in bslib. So things that have been sort of introduced in newer versions of bootstrap that we thought were really cool, and we want to bring to shiny. And one of the biggest of those is the card. So you can take a card and just give it some content. And you get something that looks kind of like this. It's scrolling a little bit because of just the size of my screen and everything. Is this a comfortable, if this is too small, let me know in the chat, but I'm going to stay here, I think, because this is fits enough on my screen. Okay, so cards, basically just like give you a border. And then it's like a way to put a little box around some content. But there are other parts of the card, too. So the first thing that happens, everything that you give to the card, basically is implicitly part of a thing called card body. So we basically take all of the children that, you know, the things that you put inside of the card, and we wrap it into a card body. And we just do that for you automatically. But now that you've seen card body, that implies that there's some other parts to the card. And there are so there's a card header. So here's where you would give your card a title, like my cool card, right. And with the with the card header, and now you have a sort of top area to the card. There's also a card footer, more information about my card. And that does the same thing, but for the bottom of the card. So this is a great place to put like attribution, or, you know, notes about a plot or something like that. And the card header is the best place to sort of tell people about what is inside of the card.
All right, if you have more than one card, I'm gonna, let's keep these, I'm gonna just copy this and paste it. So now I have two cards. Now that I have two cards, you can see that the way that this works in page sidebar is they are now kind of stacked on top of each other. And yeah, and there's a question about can the card height be adjusted the height of the content? Let's take this out for just a second. And you can see this is a pretty tall card. We're gonna talk about this in just a little bit why this is a tall card. We'll talk about, we'll kind of get there. And basically, you know, the next, next section. So it's a great question. Just hold on to it for a second.
Okay, so here we have these two cards. So what if you want the two cards to be next to each other instead of stacked on top of each other? You can see this function is listed up here. So that's probably the last one I want to use. So layout columns. layout columns is basically going to take things that take some things like your card, and it's going to put them into columns. So it's kind of like, it's kind of like row and column from shiny came together into one function where you you don't have to do so much wrapping anymore. So I can just take these two cards that I've created, and move them into layout cards. And now that they're in layout cards, or sorry, layout columns, now that they're in layout columns, they're going to be laid out in a column wise fashion, right? So we have these two cards next to my other card, so we can tell them apart. So we have these two cards next to each other. And layout columns, you can basically just give it as many things as you want. And it will just lay them out in a in a way that sort of makes sense. And until it doesn't, and then that's the time when you have to learn, you know, other other arguments to layout columns. We're going to cover that in the next in the next hour.
Exercise two
So okay, so this is that's page sidebar and layout columns. And so now it's your turn to check out value boxes. I'm sorry, it's your turn to just practice some of the stuff that we that we just did. So basically, the goal with exercise two is that we're in the process of refactoring an older shiny app that uses these, we could because we wanted to use these new features from bslib. And I've started the refactoring process by pulling out the inputs, so that if you just go find the section of UI, you can just like everything is just one line each so that you can move everything around a bit. Your task as a group is to migrate the UI section of the app from fluid page and sidebar layout to use these new page functions, maybe even a card, maybe even a layout columns in the app. And so give it a shot. So I'm gonna send everyone back to the breakout rooms. And if it and then also if you want to sort of stop at some point and get up and and take a break. I'll send a message when in five minutes basically to suggest that you do that. Okay, so I'm going to send everyone to the breakouts now go have fun.
All right, welcome back. How did that go? We could use reactions, I guess, for this, I could find them. That went well. Not well. Or you could chat.
Where did my chat go? I don't understand why every time I move around, Zoom moves everything around. Hang on. So some people, that seemed to go pretty well. I have a sense that that was also probably a little bit not quite enough time for some other people. So let's do it together real quick.
The idea was to take this app here, and number two, which is not that app, it should be this app. It looks something like this. Let me make that go away. Okay, so we get this nice, so we have kind of a sidebar layout, but also everything's kind of stacked on top of each other.
Okay, so there's a couple things we can do. First of all, instead of fluid page, we have bslib here already, so we can just start making changes, right? So we do page sidebar here instead of fluid page. Is that going to do what we want? That almost works. So we're, yeah, now our whole page is in the sidebar. So that's close, but not quite what we want.
Refactoring the app with bslib
We have a title panel, which we can turn into the title argument of page sidebar. This sidebar panel, I'm going to just move that up one, and to do that, you do option arrow up or arrow down, option on Mac or alt on Windows. So that's a super handy trick that I use all the time when I'm writing Shiny apps. So this is going to be sidebar instead of sidebar panel, and we pass it to the sidebar argument.
And now I'll pick this, command I, or I think it's control I on Windows, to get everything lined up correctly, and that puts it all in the sidebar. And then I could just start here and just take all this stuff, oops, hold on, take all this stuff out of the main panel, and the sidebar layout, there we go. So I'm feeling something, where am I, yeah, there we go, and reload the app. And now, yeah, this is certainly an improvement, right? I have the sidebar is over here, it can be hidden, and I have these things.
I guess the next step is that these, it'd be nicer if these were cards, right? So I could take this and put it in a card, and it would also be helpful if it had a title, right? So I could put a card header over here and say admissions rate, which I'm just kind of reading from the output variable, and you can see that that's going to put that whole plot in the card, which is nice.
So I'll just do that for the rest of these, card header, completion rate, and I'll move this up, and card, card header, actually, hang on, let's just do these two as cards, and then try one other thing. So once you get here, that's pretty good, so you have these two cards, these are kind of, these plots are, you know, don't need to be super, like, they don't need a lot of horizontal space. Right now, they're taking up, like, the whole width of the app, right?
So I'm going to use layout columns here, and I'm just going to, let's see, this is the way I usually like to do this, is take this parentheses and move it here, and then grab everything, command I to re-indent, and get rid of that extra line, and now we've got the two cards next to each other. So this is pretty, this is a nice improvement, like, I could live with this app. We haven't really, like, touched any parts of it yet, so if you play with it a little bit, you can see, you know, okay, the sidebar, it works, right? And this part here works as well.
Local vs. global inputs
Did anyone play with the group by? What happens here with this one? Notice there's a little divider here to kind of separate it from the others. So this input only controls this plot over here. It controls the color variable for the plot, and this is plotting the average cost over, compared to median earnings for each school, right? You can hover over and see some information.
Okay, so this, because this input controls something that's just about this plot, it doesn't make as much sense, it's kind of different from these other inputs, right? These other inputs control every plot, so whenever I change anything from these inputs, every plot in the app updates. If I change only the group by, then only the group by updates, or so only this plot updates, right? How can we fix this?
Well, page sidebar is powered by a function underneath called layout sidebar, and it's a lot like, it basically works in the same way that we've seen so far, and it's also a little bit like layout columns. So what I can do here is say layout sidebar, and I can move the plotly output in there, and I can say sidebar equals sidebar, and local inputs would go here. I'll reload this so you can see, we're getting close. So now I have basically a layout sidebar with this local input is going to end up there, right? I just have to make that actually happen.
So this is an important concept in general when you're designing your Shiny apps and designing dashboards with bslib. It's important to think about where the inputs are in relation to the things that they control. So global inputs that are in a sidebar should probably control everything on the page, and you have this option of using a layout sidebar, and you can even put this in a card.
It's important to think about where the inputs are in relation to the things that they control.
Value boxes
So there's another kind of card. It's kind of like a special card, like a card variant called a value box, and I'd like to show it to you now. So a value box, you might be familiar with these a little bit from shinydashboard has a similar function. I think it's just called a box there, and Flex Dashboard has another notion of this idea, right?
But at its core, a value box takes a title where you would say like, I don't know, average cost, maybe average yearly cost, and it's going to take a value, which here would be, I don't know, 42,400, and if you want to format this, well, because I'm typing it out, I could do that, and you get a box that looks like this. Yeah, by the way, these values pair really nicely with the scales package. So in the scales package, there's a bunch of different functions. You can use dollar, for example, and I can say 42,400 and let the scales package do that formatting for me. But basically, yeah, you have a title and a value.
There's also a theme argument where you can say basically what color or what color theme you want to use for this value box. I could choose primary or secondary. You can also use, so those are all like the, Bootstrap has this whole idea of theme colors, like semantic colors, like success. If this is a good value, you would use success, and if it's a bad value, you might use danger. You can also use basically any named color, like purple, and then there's a few other options that are available to you.
And then finally, the other big piece of a value box is the showcase. And the showcase is kind of a good place to put either an icon or a plot. And for icons, I really like bsicons, the package bsicons, which has a function called bsicon, and then I just have to remember what these are, what icons are available.
So I'm going to go to, I'm going to search for bootstrap icons, and it brings me to this page for bootstrap icons. And here you have like the whole list. And I was wanting money, something money related. And cash stack seems very appropriate. So I'll just remember that and come back to where I was and say cash stack. And now I have the cash stack showcase.
Exercise: building value boxes
So in the next exercise, it's your turn to turn a couple of those things into value boxes. Exercises for number three, it contains the start of a dashboard, I've kind of worked out all of the reactive side logic for you. And your goal is to make three visually appealing value boxes that describe the number of undergraduates at a school, the average yearly cost and the rate of completion. And there's a, you're not like completely on your own here, there's an app that I built, which is available online, or through this command that you can run in your project. And it will actually, let me show it to you.
So I can even warm it up and make sure that it's ready for everyone to come over here and look at it. And while that's warming up, let me just come back to the instructions. So the, I'm going to copy this link here into the website or into the chat. So if you want to open up this, the instructions and have them next to you while you're working on this exercise, that's a great place to do it. And I'll also make sure that I copy this into the chat when everyone goes into their breakout room. So if you're wondering what you should be doing, that's a good place to look.
So the Build-A-Box app looks a lot like this. And through it, you can customize basically all of the little features of a value box. You can do it globally. So here you could pick, let's say I want to use semantic background colors. And you can swap out the theme quickly and see what it looks like. If I want to use a plot, an icon instead of a plot, you can do that. And you can also click on an individual card and it will bring up individual settings for the card.
There's a helpful little, well, first of all, you could say, you know, like average yearly cost and you could put in the value. So 42, some made up number that I just came up with right now. And then you can use this to search through the icons and maybe find cash stack that way. And then at the top of the app, there's a show code button. And when you click on this, it'll give you the code for the three value boxes that you're looking at. And maybe in this case, you'd want to just copy this one. So that's a nice way to kind of get started exploring all of your value box options.
Okay, I'm going to send everyone to, I'm going to shuffle the breakout rooms and send everyone to a new breakout room. And we'll be back probably around the middle of the hour.
It's a somewhat involved concept, but it's useful to just sort of like talk through it and see some examples. Whereas we're going to skip the advanced carding section because that's something that you could read later and it would make just as much sense. So with filling layouts,
Filling layouts explained
let's go back to like basically everything on the web and everything that you see in a web page is kind of surrounded by an invisible box. So you know if you put something in a card then you know we'll draw a border around the box and you actually kind of see the box. But in general everything on the web is this is this like is inside of a box in some way. And block elements are things like divs and paragraphs where basically they're going to take up the full width and there's like nothing you know there's stuff above them and stuff below them and they can like contain things. So they take up the full width but they're lazy about their height which means that in general it's what tells a block element how tall it should be is basically what things you put inside of it.
So here I have a card and I have a map inside of the card and we're going to find our way down to just the UI part. So here I have a fixed page right so it's like just sort of a standard page and I'm using card basic because I want to use just Bootstrap's basic card styles and not bslib's extra fancy card styles. So card basic this card has a leaflet output and I've said the height of the leaflet output is 300 pixels but if I make this 500 pixels then the card is going to grow to be 500 pixels tall right.
So it's kind of driven the the height of the card is driven by the stuff that you put inside it. If I put in like a paragraph of text and run this like this you know the text plus the the map are going to you know that's where the height of the card will come from okay. But in dashboard layouts we we're often dealing with constrained space both horizontally and vertically so this kind of presents a problem. I'm gonna what happens if we set the height of the card and we say like you know this card has to fit in something like 300 pixels. When we do that normally the the the map that's on the inside which is too big is going to overflow the container and because the relationship kind of goes from the thing inside back up to the the thing holding it right it goes from the child to the parent and here constraining so like the height of the child can drive the height of the parent but not the other way around unless you do a bunch of extra work which is something like you know set this to be height 100 percent and and then now you're saying this height will follow from whatever is you know constraining the parent.
The the problem with this approach of using height 100 percent is that this is it's finicky and it also is the kind of thing where you have to be very careful about where you have set height 100 percent and you have to make sure that it like follows all the way down and you might have to set it in a whole bunch of different places in your in your UI elements and stuff. So so this isn't gonna work super well for us. So because Shiny deals with putting things in dashboards we came up with this this concept called a filling layout where that basically answers the question of how can we take an output or a layout or a plot and have it just know to take up all of the space that's available to it which means either growing to fill the space that it has or shrinking down to to fit inside of the space that it has.
So because Shiny deals with putting things in dashboards we came up with this this concept called a filling layout where that basically answers the question of how can we take an output or a layout or a plot and have it just know to take up all of the space that's available to it which means either growing to fill the space that it has or shrinking down to to fit inside of the space that it has.
Yeah so what I'm going to do here is I'm going to change out the basic card from that's using you know like basic bootstrap card for a bslib card and notice that I have this set so that the card is smaller than the plot by setting height 300 pixels and when we use a bslib card the plot is just going to know that it had you know know to take up this space instead of instead of overflowing. If I were to add yeah so let's add some text to this card I'm going to add one paragraph with one sentence and when I do that so I have my one paragraph one sentence you can see that the the card is still 300 pixels tall and the map is basically fitting in the space leftover available to it right so the map is a little bit smaller let me switch back and forth right so the map grows to take up whatever it can and then once we add a paragraph it's basically like these two things are taking up as much space as as they can kind of.
What if I do something where I have like two paragraphs and I make them yeah and you can see the map is going to keep shrinking rather than rather than like making the card grow it's going to keep shrinking so that you have just you know it's taking up the space that's available to it. So this idea of fillability basically what is happening here is basically what is happening here is the card is fillable and the plot fills the fills the card and if we change page fix for page fillable this is a page that takes up the viewport height so for some reason okay so like imagine this is my you know this area here is my browser window this card has now you know has now expanded to fill up the whole the whole space available to it and it actually kind of ignores its own like Harry said height should be 300 pixels but because it's filling it's going to ignore the the it kind of just means something slightly different if you so I'll we'll come back to that in a second like how to how to handle heights.
Fillable containers and fill items
So because every so that like this works really well we've seen it in a couple places where you know you put the plots into cards and if I go back to the like this you know this plot here is taking up all of the space that's available to it and this map is taking up the space available to it another place that it kind of come up came up is in this example with the with the spark line right so hold on one second so the spark lines so like this plot right now is kind of filling it has like a little box here where it's filling it up and when we expand the card and it grows then the plot grows to fill that space and then when we close the card it shrinks back down to fill just a little the little tiny space and so we use this this idea all over the place.
And the the the basic idea that like the concept that makes it work is this idea of two elements working together so it's not just about a card and it isn't just about a plot but it's about the two of them working together so fillability fillable layouts are created by a fillable container and the fillable container says you can fill this space and then and the sort of reciprocal of that is a fill item they have they are the filling layout is activated by putting a fill item inside of a fillable container and basically we kind of in bslib have filling turned on everywhere so in this example up here the page says the page is fillable the card says i'm i'm a fill item so the card can fill the page fillable and it also says i'm a fillable item so that you know this leaflet output can fill the card as well so in general you don't have to think about this too much until you decide that you don't want it right and then in those cases then you have to then you have to think about how you're going to break this relationship and that's where it becomes important to know that it's about the two things working together.
So it's either so when you when you need to kind of break out of this this sort of setup and you want something to either scroll or be a specific height or to be certain you know certain size whatever you basically have three options to break the fillability you're going to find the item and make it not a fill item anymore you can set fill equals false so there's lots of this fill argument around in bslib and you look for that and you say fill is false or you make the parent not fillable so fillable equals false on the parent and then then the stuff inside of it won't fill it or it basically just kind of goes back to being like you know the regular way that things work on the web or you can break the parent-child relationship basically like you add another div or wrapper or something that isn't fillable and you put that in the way and then they're not the parent and the child aren't connected anymore.
The other thing to keep in mind is that we we do this kind of breaking automatically on mobile devices because on mobile devices you know like if if you're thinking about so filling works both ways it works both in expanding all the content like expanding outputs and maps and plots and things to take up the full space and it also works by contracting everything down or shrinking it to fit in whatever space is available so in general you you don't really want your dashboard to just like shrink down on a mobile device it's better to kind of just go back to the normal flow layout which is where things just sort of stack and work their way down the page and so we do that for you but there are cases where you might want to have fillable fillability turned on on mobile screens.
Breaking fillability
So here's an example where you might want to break this where break this fillability so first of all so I have this card right and I have a card with a bunch of text and I have a so that's kind of this section here is the the bunch of text is here right that's this part here in the card body so I have a fillable page with the card inside of it I have an action button which is this one and I have the leaflet output and basically what's happening here is these sort of three elements are fighting for the vertical space in the card so the this you know this text here is is kind of fighting for this this wins because it's not fillable it's not a fill item sorry so this this text isn't a fill item because paragraph tags are not fill by default so it's basically it's like I'll take up as much space as you give me right and then the the map is like well okay there's after everybody else has been added to this card there's only like this little tiny space for me and and so it shrinks down so in this case we need to break fillability in some way so we have a couple options and we'll let's try them and see what happens.
So first of all I have card I have card and card body because we need to be explicit in card body if we're going to set we're going to say that card body is not fillable so we say fillable is false and in this case now so the card is a fill item and a page fillable so it'll still the card itself will expand all the way but the but I've turned off fillability in the card body and now everything in the card body is just regular like it just flows so um so it doesn't try to take up it doesn't try to shrink or grow it just takes up its natural height so we have like this you know all the text is here our button is here and then we have um and then we have the plot and the plot is like the default 400 pixels size right so that's one way you could do it and then you have a scrolling card this isn't quite what I wanted so I'm going to take that out.
And um what I was kind of thinking of is if I move the paragraph tag the paragraphs into their own div then they'll be grouped together and um and that that didn't work either um oh I know so we actually have to use card body we're going to use a second card body here and we're going to take this and we're going to move the um we're going to move the text into the into the this one card body the first card body and here we'll say fillable equals false and we'll try that there we go and now we have like the top half is kind of scrolling and then the bottom half is still the bottom half is still trying to fill so what what ends up happening is this one takes up but you know it takes up half of the card this takes up the other half of the card and um and they kind of share the vertical space.
Um filling and fillability and filling are kind of they're they're a bit tricky um and there's a basically there's an article hold on I'm going to go find the article so the the best place to like read about this and like really take your time kind of digesting it is at bslib if you go to layouts and then filling layouts we kind of walk our way through through this.
Page types with fillability
Um let's go back so there are a couple places a couple pages that have fillability turned on by default um first of all page fillable is pretty obvious uh fill basically you know like the idea is to get everything to fit into one screen um and this would be good for like a dashboard that's that's basically supposed to like take up the whole layout and um you can add a title if you want you could do something like say h2 title um you know and then basically everything is going to kind of share whatever height and width is available to it.
Um page fillable comes with with uh with some arguments that are are useful and you'll see them in a lot of different places so first of all you can decide how much padding is around the outside edge by um with the padding argument I can make these go all the way to the edge by setting padding equals zero or I could give them you know lots of extra padding by saying like something like two rem right I can um the gap is so basically these layouts are driven by a css feature called flex so you can say gap equals zero and that is going to control the space between each element at at this level at the page level so you can see that it uh you know there are three levels here there's the first level first row second row and third row right and everything in between them there's zero space layout columns also has this argument and you can say gap zero there and now you have um you know you have a really tight layout but you can make this bigger you could say one rem or um or pick another value for some reason I might want one on the page level things and two in the in the layout columns.
When you if you do want filling to happen on mobile screens you can use fillable mobile equals true and that's going to give you something that looks like this so now you know I have the filling layout and um and it continues to be filling on mobile and because I have a layout columns here I'll also have to set say I want this to be fillable on mobile as well um at least I feel like I remember that but okay for at least for the outside layout that works.
Um in page sidebar the the main area is fillable also so the same kind of logic applies you can you know do um you can use gap and you can use padding sometimes you'll need to use these to you know like if you have a uh if you have a layout that you want to kind of live at the edge imagine like a really big map that you want to put in here you'll want to set padding equal to zero.
And um and last but not least we have page nav bar so page nav bar is a lot like um so page nav bar is you know creates this let's see if we can get it there so it creates a a nav bar page where you can flip between um different sort of studio pages and um and to create a so basically these are um page number is going to take nav panels inside of the page nav bar and turn each nav panel into so here I have the first nav panel is named one and that becomes the the tab target right the thing that you click on and then you have the things that go inside of the content of that that sort of navigate that sort of page element or whatever.
Um this this naming also works for this these nav panels work in in a bunch of other places like we have nav set cards that have tabs on them you could use a nav bar or a nav tab on its own nav set bar or a nav set tab on its own and in every case you're going to kind of say what content is grouped with which uh sort of tab control by using a nav panel. Um it's hard to see here but a thing that we really like is to do something like this where you say like title is my dashboard um so give it a title and that puts the you know that puts the title up here in the left corner and then we have another um we have a little function called nav spacer and what nav spacer does is it basically just pushes everything in the nav bar to the other side um and if you put tabs to the end and then you get this kind of this nice setup for um for your tabs you can also use nav item if you want to create something in the um in the in the nav bar like a github link or something like that and um you know i'm going to show you very quickly but it's it's it's a and um you know i'm just showing very quickly but you'd want to use like bs icons to put the icon there and and make it an actual link but nav item basically makes something in the nav bar area without associating with some content that's going to be shown when you click on the tab.
Exercise five
Okay so it's your turn to do a little bit of this um in exercise five there's a few plots some of them should be familiar from some of the previous exercises but there isn't enough layout or enough space in the in the layout so your task for this exercise is to try to find a new layout that you can see these plots and you can see um you can you can see the elements and you definitely want to use layout columns and layout column wrap again and you will also want to use um page nav bar and uh nav panel. Um and then and there's one more thing which is that if you have that i'll just show you really quickly if you have like a row of value boxes for example and you want to let them define how tall they are which is a good idea usually on layout columns you would set fill false which is going to break the filling fillability relationship and it means that these this row is basically going to be as tall as it wants to be and the other rows will adapt so this is a using fill equals false is a great way it's a great thing to do when you have value boxes in in a layout columns or layout column wrap.
Okay so with those hints you're going to go into exercise five and i'm going to keep the same breakout groups it seems like it's working and check the chat if you need some hints or a reminder about the instructions i'll see you in a few minutes.
all right welcome back lots of people hanging out until the very end in the breakout which is hopefully a good sign at least that you're enjoying the people you're in the group the group with but let's let's go through the exercise of doing this together again so here's the app that you probably started out with it's it's hard to read anything right so this is one of the sort of problems with the fillable layouts is that you get stuff that looks like this there's one really easy way of solving this problem which is you can say fillable equals false here under site page sidebar and you can make that main area not fillable anymore kind of works like this might be what you wanted it makes nice big you know everything is nice and big and it takes up the whole like you know it kind of fits and then you I don't know I guess from here you would kind of work your way through and you know give these cards different heights and do all of that but it would probably be a little bit better to do something slightly different which would be to take some of these things and put them and to kind of break them up first of all between a couple different pages so the thing that speaks to me is that we have a bunch of plots and maybe the map you know this like this section here feels a lot like one of the apps that we've seen before you know we kind of have three plots together and uh and the map and this plot and the map kind of together so okay like we could go back to that layout and this feels like I don't know maybe maybe a separate table would be better for this so I'm gonna use page nav bar and I'm also gonna use nav panel and naming things is really hard I don't remember we'll just call this plots here and I'm gonna take like all of these plot outputs and the map is that yeah we'll take all of that and we'll put it in this first nav panel and then so that's good I'm gonna do can I I can't fold here oh this is not my normal RStudio setup so okay and then I'll make another nav panel and I'll call this like table because I'm not thinking too hard about these names right now but once I do that hmm we're at least gonna be in a better spot probably where you know there's less less mush and this table kind of fits okay so if we want to do that same kind of now that we've kind of split it up we can do that same trick that we just did of making some of the things fillable like we can make we could say fillable equals and I'll make only the plots panel fillable that's one one way of going about this actually kind of like this I think because then we'll have we'll end up having is we'll have this part where we'll be like okay we're gonna kind of like rearrange everything so it fits on one screen and then for the table you know it's use as much space as you need right the other thing to keep in mind here is that we have this sidebar the this sidebar argument to page nav bar becomes a global sidebar so this sidebar persists across all of the pages right it's the same sidebar and if I change the school I go to you know some other school University of Finlay and you know this is now about the University of Finlay so then inside of nav panel inside of this plots nav panel it really just kind of comes about like using our layout column wrap and I'll just say widths width equals 1 3rd and I don't know grab these and put them in here something like that and then layout I'm just gonna do a really simple version right now and say width equals 1 half and let those but these next two cards have split the difference okay and you get something like something like this that's a little better right now I can actually see everything that's pretty close we can see everything for the most part that we'd want to see and this app is gonna mostly work at smaller sizes one other thing that I could show you that you might want to do here is like you know these plots you know they don't need to be they don't need to be so tall so I can set a max height on the first column and I'll say them this they shouldn't be any taller than I'm just gonna pick a random number for right now and say 300 which is 300 pixels and let's find out if this works this is this approach is more of a by more of a like try it out and and see if it works for your layout because every layout is gonna be a little bit different so this kind of works I would probably stay I probably would go with this and then work on making these sort of like spark spark lines right and have them sort of fill that area and by the way you can also so for this card undergraduate like I'm looking at average yearly cost here right cards like value boxes have a full screen option so you could say full screen is true on any of these and it's not turned on by default because you know something that you need to know that you want to do but when that's turned on then cards also expand just like value boxes like we saw for value boxes yeah this this plot looks nice like I this is this is nice and then maybe we'd set it up so that you know you have like a less detailed view for the card or the the smaller card version any questions about this task or the things that we were just talking about fill ability now page nav bar any of those things.
Popovers, tooltips, and other bslib components
all right I'm gonna jump over to so for the next we have like 10 and 15 minutes I'm gonna show you a couple cool things this is gonna be more of a show-and-tell together so there's a we've seen so far you know you can use sidebars as a way to hide some inputs but sometimes you need and you need information that is either something that can show up when you just when you like that's kind of local to the thing that you're working on and it'll show up just when you click on an element or when you hover over something and for that you can use popovers and tooltips so popovers are basically well in both cases they work more or less the same way in terms of when you're writing the code when you're writing the code you wrap a section and they use popover or tooltip the first argument is going to be the thing that you interact with to see the popover or to see the tooltip and then everything else is what shows up inside of the revealed popover or tooltip so here I'm gonna this creates a pop an icon with a gear make sure that when you're doing using this approach that you give the icon a title and BS icons and font awesome will both set things up correctly for accessibility and so now this creates a gear and when I click on this it'll reveal some content so here's a popover popovers work well with with with icons like that or they work well with buttons you know also you can even use like a shiny action button to open the thing up notice that by default when you enable a popover it appears it's there and it sticks around.
It's there, and it sticks around. The reason that it does that is because in general, because that makes it possible to put inputs in this section, right? So let's see how we could do something like that. So imagine we have a card, and here we have a, this card has a card header, and there's a plot inside of it. And what we want to do is we want to have a popover that looks kind of like this, except we're going to actually put some inputs inside of there. So at the moment, this requires a little bit of custom classes. There's an HStack class from Bootstrap, and that kind of makes everything... HStack is like line everything up horizontally, stack horizontally. With one other class, this class justify content between, that is a flex related class and what it does is it says push everything so that they are as far apart as possible from each other. Once you've done that, it's basically saying the cost first earnings is going to be on one side and then the popover is going to be on the other side of the card header and now you can put something in here that you would use for the grouping variable. You can put some inputs here that are going to affect the plot is the idea.
Tooltips are really similar, like I said, a tooltip has a trigger element, so here I'm going to use the info circle and in the case of a tooltip, you're not going to put much in there in terms of content. It's just a little bit of content that's revealed when you need it. Help text is a good thing for this. Here I have a tooltip that's going to say, when you hover over it, it says regular expressions aren't supported. I've put that in as part of the label for a text input. You can just use this snippet or come back to this to reference it, but basically, I gave a tag list to label and then that's how we can get a couple different elements into the label area. Then you put whatever, you look for your school or something here. This is super helpful for giving a little bit of extra context around inputs. Like I said, card header and card footer are both great places to use these. You can actually have multiple HStacks. Here I'm taking the above example, using HStack to have this side and then a div, so I have a little toolbar area over here. That div then also has an HStack and then a gap. The more often I write this, the more likely it becomes that we'll end up with helper functions in bslib that would do this for you, but for now, it's a couple classes that you can put together. Here, inside of this div, I've put a popover and a tooltip. You have a popover and then maybe you have your tooltip next to it, or maybe you make them both popovers or tooltips.
Live demo: exercise seven
Let me try to do this interactively instead of sending everyone to breakouts because this is a pretty neat way of... I'll just demo the app for exercise five. No, it should be... I got out of seven. Okay, so look at seven together. All right, so what I did here is I have... Do you remember this plot from earlier, the average cost versus median earnings? I had an input, which was radio buttons, that says here you have a couple choices and it's going to control the color of the variables. Before we had that in the hidden in the sidebar, but using the same idea, I have a card and then the card header, the HStack, and then the title and the popover. You can click on this and see the input, and you can see how this input affects the plot. This is one of the reasons why they stick around, so that you can move between them, move between options, and when you're done with it, you click the X or click the trigger again, and it'll go away.
Accordions and new inputs
Another way that you can group content together is with an accordion. Accordions are sort of like nav sets, except they, at least in terms of their design philosophy, you have one accordion collects a bunch of different accordion panels, and an accordion panel has a title, and then everything else is content that goes inside of it. So the first argument is the title, and then everything else becomes the content. There's a couple interesting arguments, like you can use open to decide which accordions are open by default, and you can decide which, you know, you can decide if one or more accordions are open at a time, and you can also give each accordion panel, each of these titles, they can have icons as well. So it's a really useful way, like here's an example app where, you know, you can imagine it would be much better if these were sort of grouped into sections, like putting these two, you know, these two inputs together in an accordion that you could expand or contract as you, you know, or hide as you want.
The other thing I want to show you quickly in the last couple of minutes is a couple other inputs that we have in bslib. Instead of checkbox input, like these, if you have a situation where you want people to be able to turn something on or off, you could instead use input switch, and I'll just make all of these input switch really quickly. You can see that you can just basically switch from checkbox input to input switch, and you immediately get this kind of treatment where everything becomes a toggle that you can turn on and off.
Okay, there's also this really cool new thing that I'm really pleased with, which is an input task button, and there's a neat talk by Joe Ching called Managing Long-Running Operations, and it pairs with a feature from recent Shiny called Extended Task, but you don't need to know any of that to be able to use it. So here I have, basically I just have an action button where I have decided that instead of having this plot update whenever you change one of these toggles, I want it to update when you click the action button. So I can make some changes and then click the action button. Here's the problem with this is if, what if I like click this a few times, I've just clicked it a few times, and you can see like each click becomes a new recalculation and going back and figuring out, you know, redrawing the map, right? Input task button, you could basically just drop in for action button, and it'll do the same thing except better. So basically, when you click the button, it'll turn into a processing state, and it will give you some feedback that some work is happening. It automatically knows when that work is done, and it'll go back to its regular state when that happens. In the meantime, it won't let you keep clicking this. So I'm clicking right now, click, click, click, and nothing happens until it returns, and then it lets me click again. So this is really useful if you have something that's like a long-running task, but also you want to keep people from just like mashing the button. You know, you get both the visual indication that something is happening, and it prevents them from clicking the button a bunch.
So this is really useful if you have something that's like a long-running task, but also you want to keep people from just like mashing the button. You know, you get both the visual indication that something is happening, and it prevents them from clicking the button a bunch.
The last feature to show you is dark mode. This is like one of my favorite things of all time, and here's a little snippet that you can use to see this. Like it works really well in a page nav bar with the nav spacer trick that I showed you earlier and with the nav item. It's going to be hard to see here, but you end up with a little dark mode switcher kind of button, and you can click on that, and it actually will follow the current color scheme of the user's system and everything. So it works pretty well, and there's a lot more to it, but you can just basically drop it into your app, and then you have automatic dark mode.
So we're coming up on the end of time, and I had planned for a little bit more time for questions and everything, so I will stick around after the end of the workshop to answer any questions that you have or just to talk about Shiny or bslib or anything, but I really appreciate you being here, and I appreciate our medicine for the opportunity to talk about bslib and Shiny, and thank you to everyone, especially those who are leading the breakout groups and making that a fun experience for everyone. So thank you.
Q&A
Thanks, Garrick. That was great.
Hi, Garrick. Do you mind if I ask a question? I would love that. Thank you. With this new feature of Quarto emails, of being able to send emails by Posit Connect, do you know if in the future some of these amazing bslib features will be added to Quarto email?
Do you mean in terms of theming? Yeah, in terms of theming. Yeah, that I want to get to use the cards, the layouts, to create beautiful theme emails. I know it doesn't work because I've tried it out, but I'm wondering if in the future that would be a feature that we could use.
Yeah. So I am working right now on this idea of unified theming. So the idea that you would want to be able to quickly create an email that follows your brand guidelines or something like that. You want to be able to quickly make a Shiny, like use the same sort of config file to say like, my Shiny app should look like this and my email should look like that and my web pages should look like this. So that's definitely on the roadmap. The hard part about emails is that email clients are so weird and they're so weird about HTML and how they process things. It's like designing web content for emails is basically like a totally different world. Stuff that works in regular websites is not supported in most email clients. And every email client is weird. It's like a whole thing. So it's unlikely that the layout functions will work in emails. And it's also not our fault because HTML and CSS in emails is just very broken, unfortunately.
Do you have any, sorry for the follow up, I promise it's the last one. Do you have any suggestions for me? So I work at Apple and want to do an email for the team that has some standard theme that we use internally. And so far I have a lot of restrictions on what I can do in Quarto emails. So do you have any suggestions for me so I can improve how the Quarto emails look? Is there any package or anything? Like using mail, not Gmail, how is that specific?
Yeah. I don't know. I have not used Quarto emails much. Actually at all. Like, Quarto moves fast. And so that's not a feature I've had a chance to play with. I have used Blastula before, which is philosophically similar. And I think Rich is actually the person who implemented both. And I have done some very weird things to try to get emails to look the way that I want them. And it eventually involved actually using regular expressions and changing CSS declarations. It was not recommended. I really, I hope that by this time next year, the next workshop will be about how you can define, the project I'm working on is basically how you could just make a few setting declarations in like your Quarto YAML file or something and end up with apps that look, they're like a website, a dashboard, emails, everything just sort of look consistent. I look across these tools. Yeah. Yeah, that's the idea. Okay. Thank you very much. I'll be participating on that workshop. Nice. Thank you so much for listening to me. Thank you.
I have a question. Yeah, absolutely. So at the beginning of your slides, you had this, like a chart, it's really like a graph, right? Or flow chart or whatever it is, with bslib in the middle. Is it possible to make something like that to be a user input where you click on one of those things and then maybe you change something and then the whole diagram changes afterwards? Yeah, that would be cool. Yeah, I mean, anything's possible. That's a great idea. But people aren't doing that. No, I don't think so. This is, but it's totally possible. This is driven by Mermaid. And so this is a Mermaid graph that I did in, that I did in, and Quarto has really nice support for that kind of thing. But it's ultimately it's a JavaScript library that draws this and I have, I know that I have helped people make Shiny, I've helped people use Mermaid graphs in Shiny. So, it is possible. And then after that it's all about just writing some JavaScript. I shouldn't say just, like that's a lot of work, but it's about writing JavaScript that connects it. Yeah, that would be a tall task, but it'd be interesting if you could make each of those to be, and have the whole thing react to your choices and change. Oh yeah, totally, totally do. It's totally, totally within the realm of possibility. That's, yeah, just a question of time and making it happen. Right. Yeah, cool. Good suggestion.
Are there any other questions? I'm very happy to answer. Anything else? Hi, my name is Agata and actually I have a question, like, okay, so I am completely new to Shiny, and I am just amazed by the workshops and by the possibilities. I wanted to ask you, like, also, like, okay, so maybe if you have some recommendations for how to create a personal web page. Yeah, so I highly recommend Quarto. That's, I guess, first of all, that's where, like what I use for my own website. It's quarto.org. So if you come here, there's, this is sort of like, Quarto is kind of like the next generation of R Markdown. If you're familiar with R Markdown. Yeah, sure, sure. Yeah, I haven't heard about Quarto, but like, yeah. And this is, this is awesome. So there's a section under guide on creating a website. There's even a section on creating a blog, and I mean, yeah, so first of all, my personal website is using Quarto. And then second of all, this website that I created for the workshop is also written in Quarto. And I mostly, you know, mostly just spend, when I'm doing that kind of thing, spend a lot of time over here in the docs.
But it's, there's also the search function which you can use, and that's really helpful. But this tutorial is pretty great, and it's a good place to start.
Okay, so one more question. Like, now for my research, I'm like creating, because I'm bioinformatician, I create the pipeline with SnakeMake. And I was actually thinking if it's possible to like, either build like the Shiny app to like visualize the data, you know, in this interactive mode and so on. Because for now, like I'm plotting 1000 plots, and you know, no one wants to go to them, obviously.
So that's a great question. There's, there's a section here on interactivity too, and specifically Shiny. And you can, you can actually write Shiny apps that are inside of Quarto documents. So you could totally do that as one way of doing this. This is, this one focuses on R, but it works just as well for Python. And Shiny for Python. There is a whole, like if you're, if you're using Python and you want to stay with Python, you can, we actually also have Shiny for Python as well.
And it's, it's kind of like, we get to take, we get to take some of the, so in the R world, like some of what I went through in the workshop is limited to, like you have to use Shiny, library Shiny and library bslib. And then you get to basically you get to the same place that Shiny for Python is right now, which is pretty nice.
Highly recommend that. Also, there's this section on dashboards. So, dashboards are, this is another way that you can make these, make these, make these kinds of apps, like dashboard kinds of apps. This also uses a lot of the ideas behind bslib. So if you, so like the stuff that you learned today is still going to be, you know, like, it's, it's still floating around in the dashboard. And, and there's definitely a section in the dashboards about using Shiny for Python or Shiny for R, either one will work. And again, it makes an interactive app that, that's pretty cool.
Yeah. Okay. So, like, okay, so Quarto is also supporting, it's also working under Python, like with Python. Yeah. Yeah. Okay. Perfect. Okay. Thank you so much. Awesome. Good luck.
Embedding presentations in Shiny apps
So, I wanted to know if there is, by the way, a great presentation, and I really enjoyed, enjoyed the workshop. So, my question was, I have some previous, like, I'm a little bit familiar with Shiny, I have worked on some projects where I built like Shiny app to visualize the results of like, where I can choose different variables and get my, like, nice plots and everything. So, I wanted to build a Shiny app, which has some presentations in it, but, like, most of the presentations are not created in R in general. So, they are maybe created in, like, PowerPoint or something, like, based on, like, collaborative work someone else did it. So, I wanted to add that, like, embed it, embed that in a Shiny app. Is that possible in any easier, like, is there any easier way to, like, just use the presentation as it is, instead of, like, doing it once again, like, all over again?
Yes and no. So, I think the fundamental question is, can you make a web page from the presentation? And I don't, I'm not super familiar with, it's been a long time since I've used PowerPoint. You know, these days I, if I need a presentation I'll use, I'll use Quarto.
Right. Totally, totally get that. Yeah, I think the, so the thing is, like, if you can turn it into a web page in some way, like, PowerPoint might have an export to web page thing. That seems possible. Once you have it as a, as a web page, you can, you can use what's called an iframe. You have a couple options. If you're in Shiny, you can use an iframe to embed the presentation in your Shiny app. It's like a little bit of work to set it up so that it's, like, hosted in the, it's, like, in the right place. But for the most part, like, if you, you would use the iframe to, like, so an iframe in web HTML is basically a way that you take one web page from somewhere else and put it into the current web page. Like, technically, this block right here is a whole presentation. It's actually, like, its own web page, and it's inside of an iframe. And if you can do that, then 100% get it, you'll, it's easy to get it into a Shiny app. The hard part is getting that first step of, like, it, where it's its own web page.
The hard part is getting that first step of, like, it, where it's its own web page.
Yeah, so my best way would be creating a page from those, like, slides, and then trying to embed that on the Shiny app. Yeah, yeah, exactly.
Yeah, I've definitely, I know I've done things the other way where I've made PowerPoint presentations out of, like, Scheringen slides or, or, like, Quarto slides, where I've, like, taken screenshots and made them, like, the screenshot is the slide, but it's really just I have screenshots. That might be the easiest way. So just, like, export the slides as PNG. And then, then you have images and then you can, you can do something with that.
Yeah, that, that sounds easier than before, but thank you so much for that. Yeah, you're welcome.
Does anyone else have a question. I see a few people still hanging out. Maybe you're already, you've already moved on and went to get coffee or something. Some, some folks might just stay on if they're going to the next workshop to it's the same link. Oh, great.
All right, well thank you so much. Yeah, that was really great. This is wonderful. Bye everyone.


