Hello, everyone. Thank you so much for joining. This is Building for Mobile and Web with Expo, a three-hour workshop we're going to be doing together. I'm Josh Justice. I'll say a bit more about myself in just a minute. To start out, I'm going to talk just a little bit about
react Native Web before we jump into the code.
react Native Web is a way to write one code base and write for three platforms and more because there's lots of platforms you can write for a
react Native, but particularly iOS, Android, and the web, and that's what we're going to be talking about and focusing on today. I've actually used this approach to make a real app in the app store. It's just a hobby app. I'm not looking to make money from it or anything like that, but it's in there and it's useful and I use it all day every day. It's called Shirley. It's a to-do list app. Believe it or not, I actually made a to-do list app. There's not enough of those in the world, but I am very picky about my to-do lists, and so I decided to make an app to meet my needs. As Shirley is written and it builds for iOS and for the web, it could work on Android, but I don't have an Android device and there was one little
javascript api thing that was needed and so I didn't work through that, but so, so close to having this for Android as well. It's actually available for free, a free account, so if you want to check it out, you can go to ShirleyToDo.com on web. It has a link there to get to the iOS app and the source is available as well, and so we're going to be building out an app from scratch or the skeleton of an app, but if you want to see a real app, you can check out the source there, and one of the things that's exciting to me about this app is it's big enough that it's non-trivial, like it's got some edge cases and some complex things, but it's small enough that you could totally follow it, like it is normal
react patterns or
react Native
patterns, like if you are a
react developer, you will be able to follow what's going on in this code base, and so if that's helpful for learning, please give it a check. Fork it, take out all my stuff, put your stuff in, feel free, and again, it's free to register, so if you want to register just to see what this
react Native web app feels like, totally feel free to do that. So to introduce things, we're going to talk about what
react Native web is, then the bulk almost all of our time is going to be walking through setting up an app skeleton, the basics of an app to get responsive
design and styling and navigation and a good look and feel working. Really, everything you need to be ready to go to start adding application useful features, business logic to your application, and at the very end, we'll have just a few minutes of discussion on when to use
react Native web. I'll share my thoughts, and if anyone else has thoughts, I'm very welcome at that time as well. A note is that this is not mainly an intro to
react Native, so I'm going to be explaining enough, if you haven't used
react Native before, I'm going to be explaining enough as we go that you'll be able to follow along, but not enough to fully equip you to write
react Native code if you haven't before. So the
react Native official docs are really great for this, actually, so if you go to this URL or just go to reactnative.dev, it's a great intro to
react Native, and you'll be able to start from there. And as a reminder, if you want to get to any of the links that we share here, if you go to the workshop web page that's down at the bottom here or linked in Zoom and in Discord, you'll be able to get the links. I'm pretty sure they're clickable in the downloadable slides that I have posted there. All right, so I work at a consultancy called Test Double. It's a company improving the world's software, that's what we say. Software is broken and we're here to fix it, so if you've ever been frustrated about software, that's kind of the whole theme of our company is that, yeah, software can be extremely frustrating sometimes, and we want to help. So we do consulting. We'll join your team to help you, to level you up, help work through thorny code things and help you as we make decisions together on the code. We can help get apps started from scratch and everything like that. So feel free to hit up testdouble.com slash agency if it seems like we can help you. We work in
react,
react Native, on the web, Node, Golang, Ruby on Rails, a lot of different technologies, and I would love to help you out. I'd love to join and help you out, and I have a lot of great coworkers that could as well. So staying in touch on social media is really interesting in the last month, isn't it? Things have been changing, and we don't exactly know where things are going to go. So testdouble has a newsletter, but even more so now, it's like, who knows what social media is going to look like in a month. We would love to be in touch with you over a newsletter, and so if you'd like to hear from me or others, if you get benefit out of this workshop, you can go to testdouble.com slash newsletter and follow along. If our company really, really focuses on privacy and your information, we will not abuse that information. It's a newsletter. You know, unsubscribe works, so please be willing to trust us with your email address. If you would like, we will be trustworthy with it. So feel free to stay in touch via the newsletter there. Okay, what is
react Native Web? It's kind of a weird name that's a bit hard to follow. So first to introduce
react Native, and even before that, for
react. So
react, as you know, I'm sure, lets you build web applications. And so in
html on a browser, and hopefully my cursor shows up here for you here, in
html running in a browser, you need a button element, for example, to have an interactable button. And so when you're writing
react code, you use JSX, you create a button element in the JSX and give it all the stuff that it needs, and then
react turns that into an
html button on the page in the document object model in the DOM. So that's great. If you love working in
react for our web applications, maybe your business needs an iOS app and an Android app as well. And so by default, you're building in iOS and on Android using their specific technologies. And so on iOS, you're using a UI button, unless you're using SwiftUI, which things are different, I think. And on Android, you're using a button view on there as well. So analogous things on these three platforms. So we're building three different apps. So
react Native can help make this a bit simpler in two different ways. First of all,
react Native, the two biggest platforms for
react Native are iOS and Android. And so you can build one
react Native app, you can use a pressable or one of the many other button type things in
react Native. And
react Native, when it runs in your application, it runs an iOS application and an Android application. And under the hood, it will turn that pressable into a UI button on iOS or a button on Android. Basically, what's going on natively becomes implementation details there. You have just one code base that covers those two applications. You also get the
react programming model and
javascript. And so many or most of your
javascript libraries and
react libraries will work in
react Native as well. So that's two of the benefits of
react Native. So now we have two applications instead of three. And both of them are using the
react programming model, which is really great. But it would be nice if we go further. So that's what
react Native Web allows.
react Native Web allows you to take your
react Native code base and target the web with it. And so you're able to, that pressable that you write in your
react Native code gets turned into an
html button on the web. And so as a result, you don't need
react Web for this application anymore. That goes away. And we have your one
react Native code base that includes
react Native Web that's targeting all three platforms. So now it's not just the shared programming model, it's one code base targeting all three platforms. I see a question that says, is MUI available for
react Native, which is, say, Material UI? I don't believe MUI itself, that specific library, is targeted for
react Native. But we're going to be using a library called
react Native Paper, which is another implementation of Google's Material
design. That's part of the big, big foundation of the workshop today. And
react Native Paper works great on the web as well. So if the goal is, I want Material
design, including the very latest Material
design 3,
react Native Paper will make that available for you on web and on mobile. So you'll get a taste for it over the next couple of hours. Thanks for that question, Jan. All right. So this is what
react Native Web is all about. And maybe that image helps, but you'll get to see the specifics as we go through. So
react Native Web is the name of the
npm package. It's titled
react Native for Web on the page, which kind of, how do I say it, how to describe it? It can be used in any
react Native project, but there's some setup involved. And so the recommended way to use it from
react Native Web's docs is through Expo. So you likely know about Expo if you're in the
react Native world. If not,
react Native is the library provided by Facebook, and Expo is a framework built on top of
react Native. It's a third-party company, and they basically give you a higher level of abstraction so that you don't need to work at the native iOS or Android level. In
react Native, by default, you're mostly writing
javascript code, but there is an iOS project and an Android project, and they have their configuration files and their native code and everything like that. And so Expo removes it a bit further so that even more of the time, you can just be writing
javascript, and they provide a lot of great functionality out of the box as well. So we're going to be using Expo. Expo doesn't lock you in. There's ways to use Expo to pull in native code. There's ways to eject out of Expo to get to a normal
react Native app. And so a lot of more information, Expo docs are great and can fill you in, or I can answer questions about Expo. But again, you will get a feel, as we go through here together, of what it's like to use Expo. So it's time to walk through the layout, what we're going to be doing in general. Here's the app skeleton we're going to be setting up for an app from scratch that works on iOS, Android, and web. We're going to set up navigation around different screens and make sure that the URLs for those screens work. We're going to be setting up a
component library, so pulling in
react Native paper, as I said, to get material
design. We're going to be setting up dark mode as well, so it looks and works great all the way through the application, so light mode and dark mode work well. We're going to set up a custom theme as well. So it's not just the out of the box material
design, but we get some custom colors to make our app look a bit more distinctive. And we're going to implement some responsive
design as well. That was one of my biggest challenges getting into
react Native was, I know how to do responsive
design on the web, how can I do this on mobile? And so we're going to look into ways to do that, that are going to fit with your mental model if you're a web developer, and that's what we're going to be setting up. We're using Expo, we're using
react Navigation, which is, yeah, by far the most popular and recommended navigation library for
react Native. It works really well on the web, and
react Native paper for material
design. Again, great support on web as well as on mobile. So we're ready to go, ready to jump into the code. So let's get started. I have here the starter app repo, and again, that's available from the web page if you want to pull it down, but I've only done very little so far. It's pretty much the stock out of the box Expo app. I just installed some dependencies to be ready. I need my code formatting, so I had to set up Prettier, so it's going to tell me and format everything as I go. So let's confirm that it's running. Here's my iOS simulator, and open up app.js to start working on your app shows up. Here's my Android emulator. Cool, and it's showing up. So the first thing we want to get started, and let me just pull up my little notes here so I remind myself what I'm doing. I'm going to hide this. One second, I'm going to shrink this down. I'm going to put the chat over to the side. Great, okay. All right. So Expo is almost pre-configured to run web out of the box. If you let me stop and restart the server, just run
yarn start to get things started. And when Expo starts up, it says press A to open Android, I to open iOS simulator, and W to open web. And you may notice that it's grayed out a little bit. So let's press W and see what happens. And yeah, so it says it looks like you're trying to use web support, but don't have the required dependencies installed. So we're given this command to install these dependencies, which is a few other things. We're going to use the back-native web itself and others. Expo just doesn't want to include those by default unless you're actually using the web. So let's stop the server and put those in. I made a little command here to have them written out. I found I needed quotes around Expo
webpack config. Let's just hit return here. These are going to get pulled in. It wasn't too slow when I did this before, so I think we should be fine. But once this is the case, that built-in web command that comes out of the box on Expo should work, or we can do it from the Expo start menu. Cool. So that's pulled in. Let's
yarn start again. The project starts up, and we press W for web. All right, this is open in the browser. So I'm going to drag that browser over here. And we get the same app. Open App.js to start working on your app. So this is just the same on all three platforms. That's nice as a starting point, but it is just a very basic starting point. So we need to go from here to say, okay, cool. We've got our app running in three places, iOS, Android, and web. Where do we go from here? How do we get started? So the first thing that I really wanted to get into is navigation, because I know my app is going to need multiple screens, multiple URLs, and I need to get that working. If we can't get that working, which could be challenging, we're not going to make a lot of progress. So for that, we're going to use
react and navigation. It's the most popular navigation library for
react Native. And so I'm going to copy some dependencies here over. All the docs for these tools are really great. And so if you go to their home pages, you're going to get this information. But for this, for
react Navigation, it actually has separate packages. And so we need
react Navigation Drawer,
react Navigation Native,
react Navigation Native Stack, and there's a Babel plugin that's needed as well. So we're going to install those. It's so fun to watch Yarm installing packages. It's great. And then after that, there's a few more Expo libraries needed as well. And Expo has such a high level of adoption that these libraries have instructions. If you're using Expo, do this. And so in
react Navigation's docs, you'll see this information. And we run Expo install. And that runs Yarm add under the hood. But what it does is Expo has a bunch of these low-level libraries that have native code pre-installed. So this will ensure that the versions in your package JSON match what's available in Expo itself. So again, I'm just following the readme library
documentation instructions to install these dependencies. And these are written all out on the instructions on the conference workshop web page. So here's the page, if you're curious. So if you go to that link that I sent, you get the full written out workshop here, including any details. So if you miss something or want to come back later, you can kind of walk through that. OK. So this should be all our details, all our dependencies needed. But we need to add a Babel configuration as well. And we do have access to Babel in Expo. So let's add this in. There's a couple of plugins to add. Babel plugin proposal, sport namespace from. And when the latest version of Expo came out, Kim from Expo was super helpful for me as I was running a new issue with this. We found that this Babel plugin needed to be added explicitly. I'm not sure if the docs for reanimated have been updated yet, but we found that was needed. Reanimated is one of those libraries that runs under the hood that
react Navigation uses. So a little bit of setup required. But once it's in place, we should be good to go. So we've added this Babel config. And we do need to stop and restart our server. So let's run
yarn start again. And we're going to get started. So it started back up. I'm going to start hit W for web because you can't just reload the page that the web app is on. You need to start it because
webpack isn't started by default. But now that does reload and that shows up just fine. All right. So we need to begin configuring our navigation structure. So the way I like to do that is with just a file called navigation. This is a convention. I mean, there's so many other things we're going to walk through today. You could set up differently if you like. I'm just showing one way to do it, but it's a way that works. So I'm going to create a source folder because I like to do that. And I create a navigation. Let's see if I can type as we go through here together. So in this navigation file, there's a good amount of setup that happens here to get our initial
react navigation screens working. So let's get started. First of all, I'm going to create a couple of sample screens that are just going to kind of be placeholder-y, but just enough to give us a try. It's going to be the home root component here. And here, we're going to say constant navigation equals used navigation that is provided by
react Navigation Native, the way to get this navigation control object. And I'm going to return just enough elements on the page here to see the screen. We're going to say text, and we're going to import that from
react Native. So this is one difference with
react Native if you haven't used it, if you've only used
react on the web before, is instead of just using div tags and paragraph tags, you have a text component you need to import from
react Native. And I see my editor has done old-style import. So let's do, yes, six ones. It's just what I prefer, and I think I sometimes get errors with that. Okay, next we're going to have a pressable, which is the latest version of a button-type component for
react Native. It looks like
react Native Web had one as well, but you do just import these from
react Native like default. We're going to put text inside the button that says go to detail because we want a detail screen. And then we're going to do on press, navigation, navigate, home detail. So that's one of the ways that you can navigate with the
react Navigation libraries. We have a home root screen here, and we're going to go to home detail. Save, let me just make sure that formats, that's fine. All right, let's create that home detail screen now. It's going to be pretty similar. So I'm going to copy and paste this just to save a little time. We still need navigation, but it's going to be home detail. And this button is going to say navigation.pop. But because we have a stack navigator where it's like we're pushing different screens onto each other, pop says go back to the previous screen. And we'll see that working. We give it a try. If you've done
react Native with
react Navigation, this will be familiar. This is all normal
react Native approach. We're going to say back to home root. So now there's two screens to go back and forth between each other. Let's create one more screen. Another one that's the root that's not related to the others. Stacks other root. All right, we got three screens. Now we need to use a stack navigator. And again, I'm just talking about concepts here, but we'll get to see them running in just a second once we started it up. A stack navigator is two different screens where we can pop things on top of each other. And then we're going to have a way to move back and forth between them. So let's say home stack equals create native stack navigator. Get that imported automatically. And then we're ready to create home. So this is all the home screens, including the home root and the home detail. So we're going to return. So the
api here, and I would not remember this off the top of my head. I would need to check the docs. But it's home stack navigator. So that's the surrounding navigator here. And then we create screens under there. So we say home stack dot screen. Name equals home root. Component equals home root. And options equals title home. You'll see how the title is used. So really, this is connecting together home root, which is just a normal
react native component. And the stack navigator that comes from navigation. That's just connecting these together. I'm going to add one more screen. Very similar is the home detail with the home detail component. And we're going to say home detail in the title of the screen. So that's good. I'm going to create another stack for the other screen. Other stack function other. Let's just change all these. Other stack. And we only have one screen in that stack. But having it in the stack is still helpful. So this is another stack that's going to allow us to access that other root screen. So now we have two different stacks, but we need to put those together. We're going to combine those in a drawer. And a drawer slides over from the side to allow you to navigate in a natural way there. So we're going to create a drawer. Create drawer navigator. Function navigation contents. And in here, we're just going to return drawer navigator. In that, we're going to have a drawer screen. So the screen abstraction works here as well. This one's called just home by itself. Component is home. We're going to have an other component as other. So if you look at this altogether, what we have is a drawer at the top level that has two screens that are at home and other. And a drawer is going to allow us to navigate between them. And then home and other are each stacks that have one or more screens underneath them. So that's all the wiring together of the navigation that happens. There's one note, by the way, if you are coding along with this in the notes for the workshop. If you get an obscure error with
react Navigation, I was getting this at some point where I needed to use a prop called Use Legacy Implementation. I just Googled around for the error I was getting and that came up on helpful GitHub issue answers. That has since gone away. And so I don't feel it doesn't seem like I need that workaround anymore. But if you run into mysterious errors working through this yourself, Use Legacy Implementation is a prop that might help you. But let's see, maybe we'll be okay today and don't need it. So there's one more thing we need to do in this navigation file. And this is where we're going to actually export from the file. I'm going to create the navigation component that's the main point of this. And here, what I'm going to do is a navigation container. And in there, we do navigation contents. That seems kind of weird. Like, why are we doing that? Why don't we just inline these navigation contents right here? And what I found, we'll actually see a bit later in the workshop, was having trouble finding navigation container to import it. Let me just add that import explicitly. You'll see that later in the workshop why I separate these out. Basically, I'm going to need this to re-render a lot based on a custom hook. But what I found is that navigation container does not want to re-render. That causes problems. That actually caused an error that crashed my app. Because the browser, in some cases, was wanting to check that it seemed like something was wrong. So this separation helps to avoid unnecessary re-renders that were causing an error in some cases. But we'll see more about that a bit later. All right. So now we have this navigation component with all these screens, these multiple levels going on, but we need to hook it up. So let's put it into our app component here. What I'm going to do is remove the styles because we don't need those. I'm going to replace the contents with this. Status bar style equals auto. Status bar component just allows us to configure what shows up on mobile for the status bar. Then I'm going to pull in the navigation. That's pulled in. It looks like all those imports are not needed. So now our app is wired up to use that navigation we set up. All right. So we should be set to give this a try. So that was a lot of coding to set up the basics of navigation. Let's see how it looks. I restarted Metro, so I need to refresh. It's loading up. All right. So on iOS here, we see we've got some title bars. We have two title bars here. That is not long-term intentional, but that's an issue that we'll work around further on. Home route is shown. We have a go to detail. It actually isn't styled as a button because a pressable doesn't do that by default, but reacting to paper will help us with that a bit later. When I click on go to detail, I'm taken into this detail screen. You can probably see on the
video a nice iOS-like animation that has a lot of details. Nice iOS-like animation that happens there. I can click back on this home navigation link, or I can click on the button back to home route inside the view to go back. Now, if I click on this little menu hamburger here, the drawer slides out. This is the drawer with home and other configured. When I tap on other, the other screen, other, other, other shows up, and I'm able to go back to home. I believe if I go to the detail, it'll remember that. So if I go back, yeah, I'm still under detail there. So it remembers the state of the stack under the home screen. Let's try Android. Reload. Got my screen, go to detail. You may notice that the animation here is different. So
react Navigation is set up to give an Android natural animation there. We can still, from the drawer, go to other and go back to home. Now, let's check out web. I've got my screen. It looks the same. We're on the web. I can click on go to detail. Notice that there's not actually an animation in this case. That may either be because of web capabilities, or maybe that just wouldn't be as natural on the web. There is an animation when the drawer slides over from the side. I can still go to other, go back and forth. I think this arrow is different on the platforms as well. Let's see. Yeah, so this is a very, iOS natural styling with blue there by default. Let's see on Android. Let's see on the detail as the arrow matches what's on the web. So there's differences here in
react Navigation as it matches platform conventions. And we're going to swap out all this default
api with
react Native Paper a little bit later. But everything is working on all three platforms. Minus this bar thing we're going to come back to. The first thing I want to work on next is URLs. So check this out. On the web, when I click on detail, I go to another screen. The URL is the same. Or if I go over to other, the URL is the same. And that's not what we expect on the web. On the web, we expect the URL to change. And we'd expect to be able to use the back button to get back to previous screens we were on. Now,
react Navigation has good support for the web by default. We just need to tell it what URLs to use. And we do this with an object called linking. So let's configure this. Again, I'm checking my notes here because I would not remember this off the top of my head if I didn't. But the docs are really good. In this linking object, we have a config. In the config, we have screens, which configures our root-level screens. We give it the same keys that we use above, home and other. It corresponds to home and other up there. And now we configure each of these. So under home, we say, what is the path for the home screen? We'll put that at the root of the application. Then we have nested screens underneath there because that is a stack navigator that has screens underneath it. So we have those screens, which are called home root and home detail. So we're going to put those in. And for each of these, at this point in the nested tree, all we need is the URL. So we're going to put home root directly under that parent path. And home detail, we're going to put it under slash home slash detail. That may be a bit unexpected, but the reason for this is just like conceptually, this is just like being at slash home. But for the very root of your application, typically you expect that just to be at the root path. So I leave that as the empty struggle. For other, we're going to give it the path of slash other. That's how to get to the root of that stack. And there is a nested screen under there, even though there's only one that's called other root. We're going to just say that's directly under slash other. It's not further nested. So this is our linking config. It sets up the URLs and the nested URLs for all the places throughout our app. The place we hook this up is a navigation container. So we say linking equals linking. If I can type. All right, let's save and let's see the result. Notice our web app, as you'd expect on the web, it refreshes automatically and we're good to go. When we click on go to detail, now we get a path. We're under slash home slash detail. When we go over to other, we get slash other. So we're getting URLs that change naturally as we go. There's something else though. If, well, let me show you this. If we go to other and we reload the browser, we are taken right back to the other tab. So that makes sense. That's natural. We expect on the web. We can link directly to a specific screen. And incidentally,
react Navigation works with deep linking on mobile as well. My coworker, Louis, is working on a blog post on this right now. So I will add that on the conference workshop web page afterwards once it's live, should be soon. So if you're on the home detail page, let's try to reload from there. And notice something surprising. We don't have a back button anymore. Oh, I see in the chat, EZ is having a problem with the
audio. I'm sorry to hear that, EZ. So Paolo and several have replied that the
audio is okay. So I'm glad to hear that. EZ, I'm sorry about the
audio. You may be able to disconnect and reconnect. That may help. This talk workshop is recorded. So in a worst case scenario, you will be able to get back to the recording afterwards, but I'm sorry about that. You can ask in the Discord as well. I may be able to get some help in there. Thanks for collaborating with us. Thanks for collaborating on that, everyone. All right. So on this home detail page, when you reload or navigate to home detail from scratch, notice there's not the back button in the title bar here anymore. And if I click on back to home route, that actually doesn't work either. So what's going on here? What's going on is that the way these
react Navigation stacks work, it's not quite like the web. The idea is there's a stack that's stateful and mutable, and you're adding things onto it. So when we navigate to home detail, there's nothing that says, hey, you always start from home route. As far as
react Navigation knows, home detail is just the one screen on the stack that we want. And so what we need to do instead is use a configuration. But luckily,
react Navigation helps us out with this. There's a concept of an initial route name. And we can say home route is the initial route for this stack. What that means is no matter where you navigate into via URL or something else, you'll always start with home route on the stack. So let's save and reload. So now when we go directly to home slash detail, we see the back button and we're able to go back to home there. So that is natural and allows us to navigate around the way we would expect. It is important to call out because mobile and web navigation is not identical. That's why I'm so glad that
react Navigation exists and that the maintainers are investing in it to solve these hard problems. And so if anything seems complex to you in
react Navigation, it's because it is inherently complex and the maintainers, I feel like are doing a great job finding high level of abstractions like we're doing right now to allow us to build apps that work great on mobile and on web with deep linking and everything like that. All right, so we've got navigation for our app working. Let's just reload on mobile to make sure we haven't broken anything. When you are developing for three platforms, you do want to make sure that things are working. So reloading, we can still go to detail and we're good to go. We can go to other and we're set. Go to detail, go back, we're good. All right, our navigation is in place and this is going to serve us to the rest of the workshop. Up next, we want to make our app look awesome because even aside from the double toolbar is there, it's looking pretty plain. This is not a button. This is just text. So we need to make it look better. And when I'm building apps, for a lot of professional apps, I have public facing things, things that they want to hire consultancy like us. There's dedicated designers that are giving us specific visual designs. But when you're doing a side project or you're doing a MVP or proof of concept or you're doing something internal for your company or for employees, you may not want to style everything from scratch. And so it's great to have a great looking
component library you can pull from and
react Native Paper is a really, really great one. It works great on the web as well. So let's install it. It's
yarn add
react Native Paper. Actually, just this morning, version five was released. So we're going to jump straight into the new breaking change version. Previous versions of this workshop, I had been using the release candidates and so things are still stable. But we are, as of today, as of six hours ago, we're on
react Native Paper 5.0.0. So that's very exciting to be on the leading edge. So we install that and we're going to start the server again. You don't need to restart the server every time you add a dependency, but sometimes you do. And so plus I just have one terminal here. So I'm starting it to get it installed. So now in the app, we need to wrap it with a provider as you're probably used to import provider as paper provider from
react Native Paper. Paper provider. So this is now available and we're going to be able to use the provider for theming coming up a little bit later. But now our app is ready to use
react Native Paper. Vicky added, usual to ignore peer-depth warnings? Did that come in the installation? Yeah, you know, honestly, I have seen these warnings in
react Native in general and in Expo in particular. And I have generally not needed them. In particular,
react Native Paper doesn't have an installation step the last time I checked that required installing
react Native vector icons. I think that may differ between Expo and
react Native CLI. So for warnings like this, I would check the installation instructions for the library that you're using. I think what's going on here is that Expo automatically includes
react Native vector icons, but maybe not in a way that
yarn can see. So yeah, what we're going through today, ignoring these peer warnings has worked for me. You or others may know better. And so feel free to investigate the details of the
npm ecosystem. But yes, it is intentional to not do anything about this warning here. Thank you for asking, Vicky. All right, we got a
react Native Paper. And so there's a lot in our app to style and theme with paper for material
design. So let's see where I said... I'm going to start with the drawer first because it's pretty straightforward. So we, out of the box with
react Navigation, I'm going to reload. We get this nice navigation drawer. And it gives us even this highlighting for these drawer items. But we want to style this to fit with material
design. So let's do that. The way we can do that, I'm going to create a components folder because that's something that I like to do. And in there, I'm going to create a new file. We'll call it custom navigation drawer. So let's code out our custom navigation drawer. And
react Navigation and
react Native Paper work really well together. They both have very high levels of adoption. And so they work well. So let's get this working. I'll show you how. Relection custom navigation drawer. It's interesting that even though we're using these great libraries with great abstractions, there's still a little bit of wiring needed to put this together. Incidentally, if you don't want to code all this yourself, you can use the repo from this workshop as a starting point for you to code off of yourself. You're totally welcome to. We're going to take in the props for the custom navigation drawer. This is something we're going to pass to
react Navigation for it to use to render the drawer. In here, we need to pull out a state and navigation from the props. We do need all the props as well, though. That's why I kind of take them that way. Let's come back to this conditional in just a second. So we're going to return what's called a drawer content scroll view. This is provided by
react Navigation. And this gives it some of the logic needed to do the kind of drawer coming in and out and scrolling. And here, so in state, the navigation state, there is a state routes object. It looks like my language server is not noticing it. So we are given here a list of routes. And so we can dynamically have this drawer work off of those routes to render things up. So we're going to map over these. We're going to get the route that was passed. And we are going to need the index as well. So in here, we have, next what we're going to use is a drawer from
react Native Paper. Because
react Native Paper has a concept of a drawer. Interestingly, I think
react Native Paper goes beyond what's in Google's material
design and provides a lot of other helpful and useful concepts as well. So I love how full featured it is. Whenever I need to show something in my app, usually
react Native Paper has something to help me out. So it has the concept of a drawer. So we're going to use a drawer.item to render out a navigation drawer item. And there's a bunch of props for that. We are going to need a key because it's
react and we're looping here. So we can use our route.key. Again, I don't remember this off the top of my head. I've just used example code and looked into the APIs for these tools to see what properties are available. Label is going to be the text that shows. And we're going to use the route name. That's going to work for our purposes here. Just as I was working, I created this workshop after applications that I created. And what I found is that having an
accessibility label is helpful here for screen readers for our app. So I'm going to go ahead and put that in just because might as well add in
accessibility there from the very start since I know about it. A drawer item has the concept of active, whether it's selected or not. So we're going to specify that. Active comes from, and I like to pull non-trivial logic, even sometimes trivial logic out of my JSX. So let's create an isSelected function. So we can say, is the route at this index selected? Now let's implement that. Const is selected. Pass an index. And we say, if index is equal to state.index. So the navigation state that
react Navigation passes us tells us the index of the selected screen that we're on. And so I just pulled that out. You could inline that, but I like giving it a name. I think it's helpful for workshops or for future code. We also need an onPress to do something once we click this navigation item. And we're going to say, navigation.navigate route.name. So just whatever route in the drawer we're going to there, we're going to navigate to it this way. I think we're good there. So this should implement the custom navigation drawer with everything we need. Again, we're using some of
react Navigation things they provide, but we're wiring up the
react Native paper for the look and feel. So let's see that in use. In navigation, we need to wire this up. So let's find our drawer. Here's the drawer that we created, the drawer that has those two screens. And we're going to configure it now. We're going to say, for the drawer navigator, the drawer content, and my language server is seeing that there, which is nice. We're going to say, custom navigation drawer and import that. So we're telling
react Navigation, don't use your automatic built-in drawer with the default one. Use my custom one to render out these screens. But I haven't hard coded these screens underneath.
react Navigation is going to pass them to me so I can use my dynamic logic here to render those out. So let's save and see how this drawer looks. Pull out the drawer. And now we have a nice, big, round, tappable purple. This is Material
design 3, which is included in
react Navigation paper version 5. So this is now a custom paper look and feel for our drawer. Let's check our other platforms as well. Ooh, our app has disappeared on Android. But it's an indication of an issue. All right, we pulled the drawer and we've got that Material
design look there as well. Let's check on the web. I'm going to press W again to relaunch
webpack. Go over here, pull out the drawer, and then we've got Material
design on the web as well. So on all three platforms, you've got a nice Google Material
design. For Expo or for
react Native Web, you don't need to use Material
design, of course. All of
react Native's built-in styling is available as well. And there's other libraries for
react Native that support mobile and web as well. But if they didn't, you would need to make that work. So, yep. All right, so now let's work on the header. Let's style the header to match Material
design standards and let's get rid of this duplicate header while we're at it as well. I'm going to add a component called Custom Navigation Bar. Now let's implement that. Like with the drawer, this is something we pass into
react Navigation to customize the look and feel for the way it renders the navigation bar. But it gives us props and it gives us logic that we can work off of. Incidentally, I am using
javascript here rather than
typescript. All of these tools, as far as I know, have great
typescript support like
react and
react Native do in general. So you can use
typescript with all of these as well. Biggie says, off topic, how your language server is working? Is it based on types off of definition files or something else? Yes, so I am very limited. Again, I'm not using
typescript with
javascript, but my editor, I use Sublime Text. I'm very old and so I don't use Visual Studio Code. Of course, Language Server works great in Visual Studio Code as well, but it also works in Sublime Text and other editors.
react and
react Native and all of these libraries have great
typescript typings built in. And so the Language Server is automatically pulling those in and using those for autocomplete and for editor hints, even though I'm writing
javascript rather than
typescript. Dimitri says, which shortcut are you using for reloading the app on Simulator? Yes, so a lot of times, and some of the maintainers of
react Native, at
react Native EU, asked me about this and said, hey, auto reload works really well in
react Native now. And so I am trying to stick with that and to let the app automatically reload itself whenever possible. But when you do need to reload it, like for example, when you stop and restart Metro, it's actually Simulator-specific tools. And this is in the
react Native
documentation, Expo
documentation. It's the shake gesture on iOS, which is Command Control Z on the Simulator to pull up the Expo menu and click Reload. On Android, it's different. It's RR. So you press RR on the keyboard and then that reloads. There's some other command that I forget to actually pull up the Expo menu. And then in a web browser, you just click Reload. So it is a bit unfortunate that that's inconsistent across the platforms, but it is part of life with
react Native. But if you know it for
react Native, it'll work for all of these tools as well. You're welcome. All right, custom navigation bar. Let's implement it. We need a navigation prop, options prop, and the backup prop. And we'll see why shortly. Here, we're going to go ahead and return. App bar. So app bar is also provided by
react Native paper. You will not be surprised to know that that's part of what it provides. That's one of the most recognizable things, I think, about material
design. So we have an app bar header. All right, so underneath here. So there's a few different things. First of all, back button. I only want to render the back button if there's something to go back to. And the back prop is only present when there is something to go back to. So I'm going to do this. So only when back is present, when it's truthy, do I render this back button. And there's an app bar dot back action, specifically back action there. But you need to implement on press for it. And it's going to be navigation dot go back. It's just passing that function and directly makes the back action work. And we do need
accessibility label. That's not provided by default, but I wanted it to say back for a screen reader. Incidentally, as a side note on
accessibility, I had learned about it over the years. But about a year ago, maybe more, I started having pretty significant wrist pain. It was enough that it was hard for me to go all through the day typing or even use my phone for an extended period of time. And so for a while, I need to use voice commands for typing and voice commands for using my phone. It's iOS calls it voice command or voice control. I can never remember which one it is. But so if your app works for a screen reader where there's text versions of things on the screen, it works for voice command, voice control as well. And so I found through that, which apps were easy to control with my voice and which were not. And for my own app that I was maintaining, I looked into ways that I could make it more accessible so that I could use it. This is really great for me to learn more about
accessibility as well as I hope increase in empathy for others. And so I try to focus more on the
accessibility of my apps now. And so if you experience any wrist pain, number one, take care of your wrists, look into that, get doctor's help, chiropractors help. But then also let that flow into making your apps accessible. It is important. And it's not just people who have a permanent blindness or other kinds of disabilities. There's temporary ones like me. Thankfully, my typing is better now. I got some good treatment that really helped, but I didn't know if that was gonna happen or not. And so, you know, make your apps accessible for the sake of people that have permanent or temporary or situational disabilities. All right. So we have the back button here with
accessibility. Next, we always wanna show the title of the screen we're on. So we're gonna say appbar.content. Again, this is not something that I remember, but just checked in the
api is how to set up this navigation. It's options.title. So the current navigation item we're on, we get the option score, including that title that I specified back over here. So I get the title in. Then also we have appbar action. What I decided, I don't know if this is material
design standards or not, but for my app, what worked is to put a hamburger menu on the right-hand side to toggle out the sidebar. That way the left-hand side is available for the back action if we need it, but the right-hand side is the menu there. So we're gonna say icon equals menu. Material
design icons are included in
react Native Paper. They're available. Let's get an
accessibility label of menu as well. So that is available for screen readers and we need to implement on press. Navigation.toggleDrawer. So that's a function in the Drawer Navigator that allows us to toggle the drawer. So this, I think, influenced the custom navigation bar. So now we're gonna save and put it into place on here. So for each of our stacks, we need to put it in. And let's see here. It's homestack.navigator, screen options. So a lot of these options in
react Navigation are configurable. We're gonna say header is custom navigation bar. We're gonna copy and paste that for the other navigator as well. And for anything like this where I'm duplicating things, of course, in your application, you can extract out that duplication. One of the great things about
react is it's very easy to extract duplication because it's just
javascript and JSX. For my sake, for the sake of demoing this, and even for my side project, it was more straightforward just to put this duplication in for a few places. It was not a big deal. All right, so we save this. One more thing is we wanna get rid of the duplicate headers as well because the drawer adds a header, but our individual stack navigators have headers as well. So we don't need the drawers navigator. So let's configure the drawer to remove that. We can say screen options for the drawer. And we can say header shown false. So let's save this and see what we got. So you can see that my app is, as I'm just making changes to the
javascript, the apps on all the platforms are automatically reloading, which is really nice, really efficient. So let's check out iOS first. You see, we just have one header at the top and it shows up this way. You may be surprised to see that it's just white because a lot of material
design apps we see, there's a themed color there. But this is a difference, if I'm remembering right, in the latest material
design three. And we'll see some changes as we go along. But so that header is there. There's just one header. That's nice. We've got our menu button on the right-hand side. We click that and we can toggle the drawer. And when we go into the details screen, the back icon shows up on the left and we can go back. All right, let's check the Android next. So we've got home. Again, with platform differences here,
react Native Paper, I think, is responsible in this case, unless there's just a bug in my code, but I think it's intentional. There's differences where on iOS, you expect the title to be centered. On Android, you expect it to be on the left-hand side. So
react Native Paper is handling that difference for us to get closer to platform expectations. We still have the back button here. Notice that it is a different back icon, which I believe relates to what's platform expectations. And we still have our menu icon here to pull out the menu on the side. And if we go to web, we can see we're on the root here. Go to detail, we get the back button. And we have our menu icon to pull out the drawer from the left-hand side. So this is really nice. We've already got a nice look and feel here. Yeah, we've got material
design. But the next thing is, what about dark mode? Really awesome
mobile apps, and more and more on the web, but with
mobile apps, it's very commonly an expectation to support dark mode. Not always done, but that really gives you a lot of polish. And if you use your phone in the dark like me, you appreciate dark mode. I like to switch it throughout the day to test out my apps to make sure they work in light mode and dark mode. And
react Native Paper has great support for it. So let's check out what works. We're going to pull out. Here, what we can do on iOS is to go into settings in the simulator. It's actually on the simulator under developer menu, which is kind of weird. We can turn on the dark appearance. Now we can switch back to the app. So by default, that's showing just normally. Oh, I see I have a typo in home detail, but that's okay. Incidentally, I haven't actually looked into in the Android emulator how to go into dark mode. So we're not going to do that for the sake of the demo here and for expediency, but you can do that in there as well. Someone in my last workshop let me know that in browsers, developer tools, you can switch on dark mode. A lot of you might be using Chrome. I love Firefox. Firefox is really good. Please support the open web by using Firefox. Try it out. It's super fast right now. And Firefox and Chrome
devtools, there's an option to simulate dark mode. So you can click on that to go into dark mode. You could also go into your OS settings if you'd like to see it. We can see here that the header automatically changes to dark mode on the web, but it doesn't on mobile. So why is that? Let's dig in. First, there is an expo config. So in expo's app.json, there's a configuration that says user interface style light. And for some reason, they don't automatically let you switch into light and dark mode unless you decide to choose to enable that. So we're going to choose that, automatic. We save that. And then we do actually need to reload from scratch in expo. So let's just click reload. And now we can see that the header shows up dark. Other stuff is not, and we're going to need to style that, but we at least see some change coming through. Basically expo doesn't let your app see the dark mode setting unless you enable this permission. Let's just see it switch back and forth. If we switch dark appearance back off, we can see that the app switches. So it's now dynamic. That's nice. Just like on the web here, it's dynamic. So dark mode is showing up for us, but now we need to get other parts of our app styled to address dark mode. So one of the things is, so the app bar is provided by
react Native Paper and so it supports light and dark mode by default. But the background of our app is just a view. It's just nothing in particular. So we need to add dark mode support for that. I found in my apps that what's helpful is to create a screen background component. It's just a wrapper that handles dark mode. So let's create that. And this will show you how to hook into
react. Oh, yeah,
react Native Paper. Because we don't want to use
react Navigation's light mode, dark mode setting directly. Ideally, we just want
react Native Paper to tell us, hey, what background color, what text color should I use and style from there. So we're going to be able to do that. The screen background, let's take in style to allow it to be custom styled. We're not going to use that in the workshop, but that was just something that I found is helpful. Anytime you have really reusable
react Native components, allowing a custom style prop is generally helpful. So now we're going to get to the theme. We're going to use theme from
react Native Paper, and that gets us the current theme, which includes it's going to be dynamic based on whether we're in light mode or dark mode. From there, I'm going to say base style. So like aside from the specific style that gets passed in by the user, what is the base style of this component? If you haven't used
react Native, these objects are used for styling in
react Native. They're inspired by
css, but they're not
css and not identical. We're going to say flex one, which basically is
react Native's flex box to fill the screen. It's important for a screen background. And then we're going to say background. Ground color is theme.colorist.background. So give me the background color of the current theme, including light or dark mode. Then we're going to just return a view.
react Native view style equals base style, and then apply the style overrides, if any, and then render the children. So this is easy for wrapping around other components. So we've got our screen background. Let's put it into place in navigation. We can just pull it in here, a screen background. So that's going to wrap our home root screen, our home detail screen, and our other root screen as well. And again, if you found this is needed for absolutely every screen, you can remove that duplication yourself in your own code. So let's save. And we can see in the background, we already have a black background or dark. It's not quite black because you may be able to see the black text on top of it. So that's not ideal. We're going to need to change that. But we are getting this dark background that actually matches the title bar. Let's check on all three of our platforms. This, oh yeah, Android, we don't have dark mode on. So we'll just not worry about Android for right now. Yes, so we've got our background being styled. But what about the text now? The text is always black whether we're in light or dark mode. Well,
react Native Paper provides a text component that is automatically styled for light and dark mode as well, as well as other settings within the
react Native Paper theme. So we can just switch navigation here to import text from
react Native Paper and use that instead. Now, when we save this, we get white text on a black background. And if we switch back, we can see it's black text on a white background. And I'm saying black and white. It's not quite necessarily exactly white or exactly black, but it's the dark color, the light color. We're getting some switching here. So that's really great. All right, so now let's take a look at the drawer. Okay, so the drawer, it looks like the actual, well, maybe that text color is changing for light and dark mode. Let's see. Yeah, check it out. So because these navigation links are provided by
react Native Paper, they are changing styling accordingly, but not the background. So let's get that implemented as well. Instead of using a screen background, we're going to do something a bit different on the custom navigation drawer, and I'll show you why. Well, I won't show you why, but it's basically it's the scroll view itself that I want to style with the background color because that element's already there and that works well for scrolling. So maybe there's another way to reuse that same screen background, but I'm going to use the scroll view here. So we're going to pull in the theme again, use theme from
react Native Paper. Then what I'm going to do is define a scroll view style, a style object for the scroll view. And again, we're going to set the background color, theme.colors.background. The way the color changes is that the use theme hook causes your component to re-render when the light mode or dark mode changes that automatically triggers for you. So then in the drawer content scroll view, we're going to say style equals scroll view style. Oh, I see that I'm missing something as well. These props that came in from custom navigation drawer, that was supposed to go to here. So let me include those. Clearly, it hasn't broken anything obvious, but it's important to pass those along. So now we have a scroll view style. We can pull it. It looks like the automatic reload dismisses the drawer, so we can pull it back out. And now we have a drawer that has a nice background. Notice that it's actually the same background color as the page, but when the drawer comes out, the other part gets darkened. It animates in. It gets a little bit darker so that we can see a contrast of the drawer and the rest of the page. And then if we switch into light mode, we have a nice look as well. We can see this being darkened a little bit differently. Let's make sure this works on here. I don't think I needed to reload there actually. Yeah, so the drawer looks good on iOS as well. Vicki asks, sure, you want to spread all props, not the rest from the structured object? I believe so. I think this came out of the
documentation for
react navigation and how to make a custom navigation drawer. It's possible that that's wrong. I mean, it doesn't make sense when I think about it that a scroll view doesn't necessarily need navigation and state. So really, I may be doing something unnecessary, but the
react navigation docs will be helpful in that regard. So if any of you are doing this yourself, check the
react navigation docs. They'll have information for you. But yeah, clearly it wasn't breaking anything immediately, at least in my case. All right, so now we have pretty good light and dark mode all the way through everything we can see right now. But the next thing is though, our colors, let me switch to light mode so we can see it. So we have the default purple that is default for
react navigation paper. And that looks good, but it would be nice to give our app a bit more of a unique visual identity. I'm already using
react native paper and material
design. So there's certain parallels that people are going to see. They can tell it's a material
design looking app. I'd like to give my app a unique visual color identity. So this is where things get a little bit tricky when it comes to
react native paper and theming. So just over the course of working on this workshop, version five of
react native paper was in progress in beta and then in release candidate. And it added support for material
design three, which is also called material U. So if you're not used to the look and feel of the drawer here, that's new for material
design three. Now, the current state of things is with material
design three, which is what's used by default in
react native paper, if you want to customize colors, there's a lot of places you need to customize it. I mean, you need to customize this light purple, darker purples. You need to customize the different colors that show up in dark mode. You may not be able, you probably can't tell, but this white text here is a tiny bit purple. This gray here is a tiny bit purple as well. So to customize the theme in material
design three, it takes a lot of configuration. In material
design two, which has been around for a lot longer, maybe since the start of
react native paper, you can actually do it with one prop. You can set a theme color, a single theme color, and then all the different colors are extrapolated out of it. And so if you're willing to go back to material
design two, which you may be familiar with seeing, you can get a lot of theme customization with very little work needed. So for the sake of this demo, we're going to do that. That way, you're going to get to see a nice different look and feel. And if you want to go with material
design three, they're talking about whether they can add a single prop. I asked about it in our GitHub issue, or maybe in the Discord. And they're looking at the possibility of having a single color value to theme all of material
design three, but it's open source maintainers, and they have limited time. So let's look into dropping back to material
design two, which still looks great, to get the ability to fully theme it very easily. All right, so what I'm going to do is make a new file called the use custom theme. We're going to do this in two steps. First of all, I'm going to set up a theme to use material
design two. And actually, when you have a custom theme, you have to handle light and dark mode yourself. So there's a little bit of work there. I'm going to get that working with material
design two as one step. And then in the second step, we're going to add in the coloration. And after this, we may be close to a break point that might be good to take a little break. So we'll see. All right, support default function use custom theme. In this hook, we're going to first say const color scheme equals use color scheme. So this is provided by
react Native. And when you want to ask, is it light mode or dark mode directly, you can use use color scheme to get that information. And that custom hook will re-render and cause your components to re-render when that changes. I'm going to default this to light. I forget if I saw that sometimes it returns null or if I was just being extra safe. But this way, at least we're sure. I think maybe delay as well. I don't remember. This is coming out of open source code that I created myself. But this way, we're sure that we always have a color scheme value. Next, we're going to say, what's the base theme? And there's actually two different themes. Let me import these. So in
react Native paper, it's MD2 dark theme and MD2 light theme. So these are two different themes. So when we're customizing the theme, we need to return one or the other of these, depending on the situation we're in. And so I'm going to say, what is the base theme? If the color scheme equals dark, let me use MD2 dark theme. Otherwise, use the MD2 light theme. And then for now, we're just going to return the base theme. We're going to modify this a bit later. I'll say to do add a custom theme color. But for now, we're just returning it. So we need to use this custom theme. We can do this in app.js. We could say const theme, use custom theme. Then we say in the paper provider, the theme is. And again, this will re-render once we change from light to dark mode. So when we save this, this is going to use our custom theme that's using material
design 2 coming from
react Native paper. We save, and let's check out what we got. So in the simulator, this may be the material
design you're used to that you're familiar with. That's super bright color at the top. It's purple by default in
react Native paper. When we open the sidebar, we have a purple tint to the navigation items here. And these look different because this is the look and feel for drawer items in material
design 2. Let's go back to Android and bring them back into the mix and take a look here. We have that purple material
design top. We got the sidebar. It looks good. Our back button works as well. Looking good. You see that now that in the theme, now that there's a rich, deep color at the top, it's white text and links and stuff at the top. And on the web, that looks like they didn't automatically reload. So let me reload that. I got something wrong. Oh, it's maybe because dark mode. Yeah, let me switch back to light mode. Yeah. So something interesting, and I was kind of surprised by this when I was first working on my app and using
react Native paper with dark mode is you get that vibrant color in the header in light mode, but in dark mode, it's gray instead. That's just part of the style. You don't like it, you can implement it or tweak it yourself. I wanted just a nice looking style out of the box. When I pull over the sidebar, we've got that purple look on the web as well. And notice that we do have, if you haven't seen it, the nice animation, the ripple animation when we click on any of the platforms. So we're on material
design 2. We have a nice purple color, and we do still have the purple in the sidebar there. In dark mode, that's just the styling. So now we're ready to add a custom theme color. So let's do this. You can look this up. There's a link in the exercises there for it to look up hex codes. You may have tools to look up hex codes as well. I'm going to say const theme color equals, this is surely my to-do list app, the bright green color that I got. F4CAF50, you can fill in any color you want there. Emanuel asks, does it automatically pick up the theme of the system or does one need to code that as well? Emanuel, if you want to clarify that question, if that means light mode or dark mode, that is automatically picked up by
react Native. If that means that your system, you've chosen colors for your system, I haven't looked into picking anything like that up in
react Native or in
react Native paper. So someone else might know more or the docs might know more, but I'm not aware of a way to pick up system theme colors, but it might be out there. All right, so for our theme, we want the theme of our specific app here, which I'm choosing as surely green in this case. You can choose a color you like. So what we're going to want to do... Oh, this is the wrong file. App.js is not what I wanted. I wanted to add in use custom theme because I want to use custom theme to give me the colors that I want. All right, so we've got our base theme here. What I want to do is, what's our customized theme? We're going to return that. So I'm going to spread out the base theme props, but what we're going to override is colors. And here we're going to spread out the base theme.colors to get all the default colors there as well. But so far, this should be identical to what we had before as well. But then we say primary theme color, setting the primary color of our app to this theme color. And this is the thing that's different in Material
design 3. There's not yet a way to specify one property of one configuration object to change the color and to get all the colors of the app to go around. That's only available in Material
design 2 in
react Native Paper right now. So let's save and let's see what we got. On the simulator, we've got green now. We got Shirley Green. And actually,
react Native Paper sees that that's a brighter color and it gives us black instead of white for the text up at the top. You can see on the sidebar there, we have green for these items. And if we go to dark mode, let's see how it looks. The dark mode still doesn't use a color at the top because that's default Material
design theme. But in the sidebar, we do still have the green. If you added buttons, well, you'll see when we add buttons a bit later, those are styled to the color as well. So that theme color does still come out. On the web, we've got the color. Check dark mode. Looking good. And let's check in on Android as well. We got our color. So it's looking good. Our app has its own kind of visual identity, at least to my
standards, someone who doesn't want to style all the styles from scratch. All right. Cool. So let's pause before we take a break and look at where we are. And we haven't added any app-specific functionality, of course. That's not the focus of this workshop. But we wanted to create a framework, an app skeleton, for you to build on to make an app that looks and works awesome. And what we have so far is a really good place. We have an app. This is already better, honestly, than any apps that I've written from scratch, other than using this setup. We have a nice-looking feel. Button is not styled yet. We'll do that a bit later. But we have navigation. Navigation that works on all three platforms, lets us to get around to different screens. Remember that on the web, we're getting URLs as well. So that's good for bookmarkability and for browser back button and everything like that. It looks good. It's animated. It has material
design. It supports dark mode as well, the save your eyes, which is really great. And so, yeah, we're in great shape. We've gotten a ton out of the box so far, from
react Navigation and from
react Native Paper. It's a really, really great high level of abstraction to build on that lets us target all three platforms with the same code base. So that's super exciting. So we're going to take a five-minute break in just a second. After that, we're going to come back and talk about a few more things. Responsive
design. Our web browser, even on my monitor, which is not that big, this can get very big. So how do we make this responsive and use the space a little bit better? A few different things we can do, including the navigation drawer. And I have some approaches that I've done that help with some of the abstractions that are not available by default in
react Native. The other thing that we're going to talk through when we get back together is platform-specific functionality. So what do we do? Not everything is available on iOS, Android, and on the web, especially on the web. Browsers are locked down for a reason. And so how do we handle functionality in our... If we have one code base here, how do we handle situations where things are not available on the web? Or maybe we just want things to look or feel differently on the web or on mobile. We'll handle that as well. And we'll take a look through my Shirley code base for some examples. Finally, what we're going to do is wrap up talking about the pros and cons. Once we've gotten a taste of actually building in
react Native Web together, we'll talk about when would you use this for a real project and when would you not? Clearly, people still use
react on the web instead of
react Native Web for all cases. So when should they? When shouldn't they? And I tend to not be very prescriptive, but I'll share my thoughts on the trade-offs and pros and cons. And if any of y'all want to share your thoughts as you go through, be glad to have that as well. Let's get started with our second portion of our workshop. And our next focus is responsive
design. So just in the last few minutes, I added some repeating text here to show that the text goes all the way across the window. And that's very, very wide. And that's probably too wide. That's probably not very useful. So what we'd like to do is apply some responsive
design here. And I'm a very basic designer. I have only very basic knowledge and ideas. And so the idea of a centered column is what comes to mind for me. I want my content to be centered in the window so that I can see it. And so it's not so wide that it's unwieldy and hard to work with. So let's look at how we can do that. We can create a centered column component that's reusable in multiple places. Let me pull the instructions back up. Yeah, center column. And styling of this is actually pretty straightforward. So export default. Sorry, I'm getting sent back and forth between different apps. What is going on here? Type in the meeting chat. Oh, well, function center column. We're going to take in column style. And again, we're not going to use this directly now, but just for the sake of easier style ability, we take in children. So we're definitely going to want to be able to pass children into our columns here. And we return. We're going to return as a view. Style equals styles column. Let me define the styles down below before we put it in place. So if you haven't used
react Native before, this is how we create reusable style sheets. There's a style sheet
api. You call stylesheet.create, and it happens at the top level of a module, and you can create styles. And you use a
javascript-based
api here, where you can create different styles you can apply. So we'll call one column wrapper, and we'll call the other one column. So the column itself, and then a wrapper around it as well. So what we're going to do is basically set a column in the middle that's going to be a fixed width, and then the wrapper goes further out, and we specify it so that the column is centered within the column wrapper. So what we can say is for the column, max width of 640. You can pick a value. You can play with the value to see what works for you. But let's say, okay, 640 pixels, which are device-independent pixels. It handles 2x, 3x higher resolution screens, but 640 pixels is the width. And we say flex one so that it fills the full height of the area that it's in. And then in the column wrapper, in here, we're going to put information to make it centered. So we're going to give it a flex one as well for it to fill its containing area. That's not identical to how Flexbox works on the web, by the way. So layout is a Flexbox-inspired approach in
react Native, but it has a slightly different
api. And you can check the
react Native docs to find out about that. Flex directions row because we want it to move from left to right. And then we say justify content center. That's what's going to center the column inside the larger containing area. So we're going to have a 640 pixel wide column centered. And so now we need to implement that. So we use a view here. The outer view is styles.column wrapper. That's how we reference that style. And then inside it, we have a view style equals styles column. And we also allow the column style that's passed in there. Children. So these two nested views is what's going to get us that centering functionality. So let's take a look. Oh, we haven't used it anywhere yet. That's right. You got to use the center column. So let's center all the screens in navigation. Incidentally, usually in my app setup, I wouldn't have the whole contents of all the screens right inside my navigation file as well. But I do this just for the sake of ease of finding things. Because these screens are so small, this kind of puts it all in one place, just for the sake of demoing here. As usual with
react, you can extract things out into separate files whenever you find that it's useful to do so. So I'm going to put this center column here. And I'm going to put it inside the screen background. That way, the light and dark background extends all the way to the outside. And it's just the contents that are centered. As I've said several times, if you find that you're duplicating this a lot through your code base, you can create your own abstraction to put it in one place. Sometimes when you have something like a flat list scrolling, the way this all works out isn't quite the same. So I like to wait a little bit before I create an abstraction like that. Let's save and see what we got. All right. Our web page is a little reloaded and we've got a centered column now. And that text wraps with margin on the left-hand side and the right-hand side. And if we use, you can shrink the window. We can see that it's staying centered. And if we get narrower, we see that the content just fills the whole area. That's why we use the max width there so that it's like, oh, yeah, it's totally fine for the column to be narrower as necessary. But we just max it out at 640 pixels. Let's see how this works on mobile. Our mobile app, I'm going to switch back to light mode just for the sake of parallel here. So we're not distracted by the styling difference. It looks like that didn't reload to get our new content. Let's reload that. Oh, it's the home detail that I put that in. Okay, we go to the detail. That's all wrapping just fine. It's not extending too wide or anything like that. Same here as well. It's going full width. Now, to make sure that the dark mode background extends all the way out, let's switch to dark mode in the browser here. And yes, our dark mode setting extends all the way to the full edge of the screen. So that looks good. Incidentally, I'm not going to demo the app in iPad simulator or on an Android tablet. But once we've handled responsive
design, we're coding just the size of the viewport. And so our app doesn't care if it's web or tablet or what. So once we have responsive
design working, it's going to look great on all screen sizes on web and on mobile. Incidentally, the app pulls up just fine on mobile on the web as well. Let me just show you that. Just so you can see how versatile this is. In a mobile web browser, we can go to, there's my personal website. We can go to that local host URL, and the app is there. It looks good. It's non-animating like just the web browser, but everything still looks good. So people on mobile can use your mobile native app, or they can use your mobile web app. All works great. All right, so that was a very basic need for responsive
design to get a centered column. Let's look for some more
advanced needs as well. So something that I like and that I use for my app is the idea of buttons. So it's very typical when you've got like a form you're editing, to put buttons left and right, like next to each other horizontally. But on mobile, it's more typical for them to be above one another, because screens, especially in portrait mode, screens are narrower. So what we want to do is to have buttons that are one above each other on a smaller screen and next to each other on a larger screen. So to do this, things are a bit more complicated. Now, if you've done responsive
design on the web, you might be used to media queries and the idea of breakpoints. So you can say, hey, if the screen width is smaller than this or larger than this, apply these styles conditionally. Now, media queries are a
css feature, and they're not included by default in
react Native's styling approach, because it's not
css. It's just
css-inspired. There are a lot of different libraries for styling you might use in
react Native, and a lot of them that are kind of medium-sized, like they're unlike
react Native paper is a very high level of abstraction that gives you all these components ready to go out of the box. If you're using a library that lets you build your own styles, but with adding some more features, probably it has responsive
design built in. I like the option to be able to go very low level with that. And so I actually created a very small, very low adoption library that allows us to do responsive
design with
react Native, and it creates what I think is a good abstraction. So I'm going to show you how to use that. You can custom code this yourself by getting the
react Native screen size and adding conditionals in, but I found that tedious and frustrating, and I wanted a nice abstraction like media queries that I could work off of. So let me show you that. And just know you're not locked into my personal library for responsive
design. You might have another library, or you might be able to code it yourself as well. If I can code it, you can definitely code it, that's for sure. All right, so let's quit out of here, and we're going to add the library. So my library is called
react Native Style Queries. It's like media queries, but it's queries. It's conditionals for your styling in
react Native. So it's
react Native Style Queries. All right, so the next thing we're going to do is to create a file called breakpoints. Right now, we're only going to need a little bit of information, but we're going to be more as we code more. Breakpoints.js. Right now, all we need is the value, the medium breakpoint. Eventually, we're going to have small, medium, and large sizes. But right now, breakpoint medium is all we need. So let's add that in. I've definitely found you don't want these sizes to drift and get out of sync all the way through your application. And so when you're styling off of breakpoints, you probably want to centralize that logic in one place. So now I'm going to create another reusable component. I'm going to call it button group. It's the idea of any time you have several buttons together, I want this responsive
design functionality. So let's code that. Button group. Children. And we're just going to allow those buttons to be passed in as children. So let's just start out with a basic view around it. Children. And now we need to decide, how are we going to implement that responsive
design functionality? The way we can do this is with
react Native's Flexbox implementation. If you've used Flexbox on the web, you know, and even from what we just saw, there's a flex direction. Let's you say, is it going to work? We just saw there's a flex direction. Let's you say, is it in columns or is it in rows? And I think that's exactly the property we want to change responsively. Are we going with organize things in columns for smaller screen sizes or organizing things in rows for larger screen sizes? So let's work on that. With
react Native style queries library, I like to conventionally, just like usually with
react Native styles, you create a styles object at the root level. I like to create a style queries object at the root level. And like with styles, you have named concepts here. So you say button container. You want to style this button container. The difference with style queries is instead of one object assigned to that name, you have an array of multiple config objects. And here's how they work. First of all, if you have just an object that's directly under that array, it's applied unconditionally. So these are our unconditional styles, our base styles. And with mobile first
design, it's usually a good idea to start with the smallest screen size styles first. So what's the defaults? The default we want for on mobile is flex direction column. So on small screen sizes, we're going to have columns. And now we say, okay, now we want to reverse the direction when it's larger. When the screen size is at least so big, we want to change the conditions. And so there's a
data structure you can use for this, but
react Native style queries provide some helper functions that make it just a little bit more readable. And so I'll import one of those. Screen width min comes from
react Native style queries. Here where you can say is, okay, what is the minimum screen size? And in this case, we want to use the breakpoint medium. So what we're saying here is basically always apply these styles, but then if the screen width is at least breakpoint medium, apply these styles on top, potentially overriding the base styles. And what we're going to override is we say flex direction is row. And then also we want to justify content to flex end. That in a default left to right language, I shouldn't say default. In my default, which is left to right languages, flex end is going to align things to the right. So if you're looking at the screen, it's on the right-hand side. And that's very typical since early Macintosh days, 1984, the action buttons are aligned to the right. And so that's going to look good. So again, what we're seeing here, and this is the
api that
react Native Style Queries provides, a declarative way to say here's some unconditional styles. Here's some conditional styles to apply on top of it. If the screen width is at least this width. So now how do we use these and put these into practice? We have a styles object in here and we say use style queries. That comes from
react Native Style Queries as well. You pass in the style queries configuration and you get styles back. Styles is a normal
react Native Style type of object structure where you can just say view style equals styles button container. So you can think of it like flattening. Style Queries has these arrays with this conditional, multiple logic that might have conditions. Use style queries takes that in, it runs as a hook. So it runs in the context of a component. So it has access to things like what is the current screen width and other properties like that. And it flattens these down into like what is the one set of styles for button container that is then ready to be applied on the view there. So this is going to cause our app to re-render as the screen size changes or browser size changes. That's going to change these styles and apply them conditionally depending on where we're at. So we have our button group now. Let's see it in progress and then I think that'll help you to visualize it. But we do need to put the button group into use first. So let's go into home route here. And I think what we're going to do, we've been using this very basic pressable now. But now that we have
react Native Paper, let's go ahead and use a
react Native Paper button as well. So we're going to remove this. I'm going to put the button group around it first as that wrapping container. And then we're going to take in a
react Native Paper button. So we're going to call it button. Let's look at the properties here. There's a mode outline that makes this first button outlined. And we're just going to call it button. And we're going to have a second and a third button there just to have three of them. We're not going to have them do anything. We just need some buttons to visualize this. And then for this last one, we'll say mode contained, kind of like it's the primary button. We're going to give that one the on press where we say navigation, navigate, home detail. That's what we were doing before. Go to detail. Save to get that formatted. So now we have three buttons in here, but we've surrounded it by the button group that we're hoping will give us responsive
design. So let's take a look first in mobile. Q&O says grid instead of Flexbox. What do you think? So I'm not actually sure if
react Native has
css Grid. Let's take a look and see. Let's take a little sidetrack on that. Because remember, what's available in
react Native is not
css. So nothing by default comes over from
css unless
react Native has implemented it. That's one of the interesting implications. And I'm going to come back to that in our summary. When we're building a web app through
react Native Web, we're generally not using
css directly. We're using
react Native styling, and
react Native Web will turn that into styling for the web. So if you were to use
css Grid, there might be a way to get that working in
react Native Web, but then it would not work on mobile. But let's see if that's available. When I search for grid in the reactnative.dev, I don't see any results. And so let's take a look at guides. This is where you'd want to go if you're building in
react Native, including
react Native Web, to find out what's available.
design, style. So here's where style is. We have layout with Flexbox. And again, I don't see references to
css Grid or anything based on that. I'm sure there's open source
react Native styling libraries that have grid functionality, but I just haven't looked to use them before. So yeah, this is a very important implication of using
react Native Web is that you do not have
css available to you. You need to approach things in a different way. Cool, that's a great question. Thank you for that. All right, so let's take a look at the mobile app. Again, it seems, oh, that's a web there. Let's look at the mobile app app. It's disconnected from Metro. Did I restart the server? I did not. Let's start the server back up. And I reload here. It loads up. And then on mobile here, there's the buttons one above each other. They don't have any spacing between them. We'll come back to that in just a second. I wanted to set up the basics to start. Let's check on Android as well to make sure how that looks. Go back, reload. Loads up and the buttons are one above each other. So for these small screens, so let's check on web. On web. Again, I think because I killed the Metro server, it did not reload automatically. So I can reload now. Oh, yeah, I got to press W to start up
webpack when I restart Expo. So I press W. That's restarting. We reload here. And now the buttons are next to each other, aligned to the right. Remember that this is the size of the center column there. So we're getting our responsive
design on a smaller viewport. They're above each other on a larger viewport. They're left and right. Let's check this out by growing and shrinking the window. You may find that actually allows us to shrink. If you have the penny in your browser, it may restrict you and you may not be able to go narrow enough. It looks like mine does, but something that can be helpful when you want to be able to go really narrow. I like to put the browser developer tools to the right-hand side and that way I don't have to shrink the window. I can just grow and shrink those to see. So you can see that our app responsibly, when it gets wide enough, the columns turns into rows and the buttons are aligned and they're aligned to right as well. Now, that doesn't look great. It would be nice to have some margin as well. So let's add some styling there because that shows a bit more non-trivial layout options. Let's add this in. Again, this navigation.js file is getting pretty big, but let's add it in here just for the sake of getting it working. We're going to find some style queries as well. We're going to style buttons here. We're going to give it the array because we have our multiple styles to apply in different conditions. By default, I want a margin of top of 10 because that's going to keep this off of the text right there and give us a little spacing. In general, I just want some space above those buttons. And actually, that way in column mode, there's going to be a space above each of the buttons. So either way, I do want that spacing on the top. But then let's add a condition. And if you're doing mobile-first
design where your small screen size is the default, screen with min is what you're going to most typically use because you say, only when we get bigger than this size should we apply these conditional styles. So what I'm going to say is, for larger screen sizes, I want margin on the left so there's space in between these buttons. I don't want that on smaller screens, though, because I don't want a margin on the left here. That will look kind of weird. So I'm going to go ahead and change that. I'm going to go ahead and go ahead and change that. I don't want that on smaller screens, though, because I don't want a margin on the left here. That will look strange. I want it to be equal on the left and right. So we're going to say, for larger screens, margin left of 10. Now we need to apply these styles to the buttons. So I'm going to pull these in here, const styles equals use style queries, style queries. Now from these styles, we're going to say, style equals styles button, button. Now we save. Let's see what we got. So yeah, we now have a space in between these buttons, so that looks a bit better. On the small screen, we have space above it. Now notice the buttons do still go to the very edge of the screen. That wasn't something that I wanted to get into. Adding padding around something is not too hard. That's pretty easy. But where you put it in your app depends on what you're doing and whether you're using flat lists and things like that. So that's all pretty typical
react Native styling. What I wanted to show was the responsive
design of having this margin here show conditionally only when you're on a larger screen. And so when we get down to a small screen, it just flops around. And really any style attributes you want to change, you can put them conditional based on the width of the screen, based on responsive
design. So we've got some nice buttons that look very natural on smaller screens and on bigger screen sizes. And again, that would work just great for iPad apps and tablet apps as well. Also, when you have a split screen in your tablet, if you have a small app on the side, like I know works on the iPad, it'll scrunch down to a smaller screen size and work like it works on the iPhone. It'll all work out well. All right. So another responsive feature, it's kind of different, but we want to uncover it, relates to the drawer. So on small screen on mobile, it's nice that the drawer collapses and is not shown. On a bigger screen, though, imagine this window goes all the way across. We have all this space at the left and the right. It's kind of tedious to have the drawer collapse. It would be nice if we took advantage of that screen space to just always show the drawer on a larger screen size. And that's something we can handle. We have access in
react Native to the screen width and
react Navigation has a property that lets you say whether the drawer is persistently visible or whether it's toggled. So let's look how to implement that to get the drawer toggling. This is something actually, there's been some bugs over the course of a couple of years I've had these apps running where issues were found here. But folks maintaining
react Navigation did a great job. Some of us in the
community collaborated and found, I don't know if I helped, but they helped, and found a solution, a workaround. And they've fixed bugs since then in
react Navigation to get it working. So I'm so thankful for all these collaborators in the open source world to help us to be able to make a cool app like this. All right, so let's get this implemented. We're going to need to implement more in the breakpoints file. So I'm going to copy and paste this over here and then kind of talk through it. What I've added in now is two different breakpoint values, medium and large, 429 pixels and 600 pixels. Again, device independent pixels. So this is what's going to tell us about when we go from small to medium and medium to large. We don't need a number for small because the starting point of small is zero pixels. If there is a screen, if there is a window, it is small unless it's 429 or unless it's 600. So there's these different breakpoints. I also gave names to them, small, medium, and large. These are just strings so that we don't have to hardcode those strings throughout the app at risk typos. It's nice to be able to have constant values for that. Then I've added a hook, use breakpoint. And what this is doing, it's using the use window dimensions hook that comes from
react Native to allow us to get the current width of the screen. And then I conditionally return the name of the breakpoint based on the breakpoint that we're in. This just kind of creates a little bit of an abstraction so that I don't need to use window dimensions and do comparisons all throughout the app. I can just use this custom hook, use breakpoint, to get the name of the current breakpoint that I'm on, if that's helpful for me for coding logic off of it. Because in this case, we got conditional styles when it's
react Native style configurations with
react Native style queries. In this case, we don't want styles. We need a value that we're going to pass into
react Navigation. So we can't use
react Native style queries. We need the values ourselves to be able to code logic off of it. One of my favorite things about
react hooks is the fact that it's so easy to create custom hooks like this to create a simple abstraction. So we don't need to repeat this conditional logic all throughout the app. I can wrap use window dimensions with use breakpoint. And now I have a very nice usable hook I can use all throughout the app. Really, really love that. All right, so with this new breakpoint logic, we can see how to configure the drawer to be conditionally present all the time. So let's go down to our drawer navigator. Where is it? There it is, our drawer navigator. Actually, and specifically as navigation contents. So we're going to get the breakpoint equals use breakpoint. So it's going to give us the current breakpoint value. Then I'm going to define a constant here, drawer type. I have trouble saying the word drawer. Breakpoint. I'm going to test. If breakpoint is equal to large, and I'm importing large, that constant from breakpoint is there. So if we're on a large screen, permanent. We use a permanent drawer. Otherwise, what's it called? A back drawer. There's actually, it's not just permanent or not. There's like several different types of drawer style. Like sometimes it overlaps the screen. Sometimes it pushes the screen over. And so there's some differences there between the different platforms. This was related to the bug we found. We found in the
community that if, when you were toggling back and forth between a drawer that was permanent, sometimes, the back option was the better other option to use. It avoided some issues where things got weird or stuck or got pushed over twice the amount or something like that. That's all implementation details as far as like, oh, what configurations are going to work here? But we found that this configuration at one point in time worked great and it still does. So we have a drawer type configuration now. And all we need to do is pass it to the drawer navigator. Drawer type. And we're using that ECMAScript shorthand where now the drawer type key is passed in and it's the value of that variable is passed into the value. So let's save and see how it works. Let's look at the web first because it's easy to get a nice wide in size. So we see here, and I'll reload the screen just so you can see it. From the start, we have the drawer always visible. Even when we're moving around, going to the detail screen, the drawer is persistently visible, making use of that space. So that works out really well. Now let's see what happens when we shrink the window down. When we shrink it to small enough, and that's configurable value, the drawer disappears, and now it's toggleable. Now we can toggle it in at smaller widths. But if we get wide enough, it becomes persistently available. And actually, even if we're toggling, when it's toggled out, it shows up fine. It goes back and forth between being permanent and being toggled open, and then we can toggle it back. Let's take a look on mobile as far as a smaller screen. I mean, I think it automatically reloaded, but let me reload just to make sure so you know that we're getting the latest code. And we're getting the latest code. So on this small screen, it toggles out from the side just fine. And let's make sure we're good on Android as well. Small screen toggles out from the side. So we're good. Cool. So this was really exciting to me because this gets us from the point where it's like, oh, you know, beforehand when we were, when the sidebar was already toggled, it looked awkward. It looked like, oh, yeah, you've taken a mobile app and you've scaled it up for a web browser, for a larger screen. The same thing would happen on a large tablet. But now it looks intentional. It looks like, oh, on a large screen, oh, yeah, you just plan to have the left-hand sidebar there. And on a small screen, oh, you just plan to have it collapsible. And in fact, we can switch back and forth and get nice dynamic behavior on the web. The same thing happens, depending on the screen size. If you're on a tablet where it changes, you know, in portrait mode, you might have a toggleable sidebar. And on landscape mode, it may be permanently there. But whatever your sizes are, you're going to get the right behavior for that screen size. Works out really great. There's one other thing on the toggleable sidebar that I want to do, though. That is related to this menu icon. So when the sidebar is permanently shown, this doesn't do anything. It's just always shown. It doesn't function. And so not only, I mean, I don't need it to do anything. I don't even really want it there. It's kind of confusing to have a UI element that's not needed. So we can conditionally hide this on a larger screen size. So let's take a look at how to do that. We're going to go in our custom navigation bar and we're going to pull in the same logic using the hook. Const breakpoint equals use breakpoint. Oh, that's interesting. That's not automatically importing that. I wonder where that is. Language server. Not always perfect. Import from breakpoints. Okay. So we've got our use breakpoint hook there. And then we're going to, again, define a custom value. Show drawer toggle. Do we want to show the toggle button? Well, if breakpoint is not equal to large, we want to show the toggle button. So smaller sizes, show the button. Once we're at large though, don't show the button. That's what that conditional is going to give us. We're going to take this and we're basically going to just wrap this action button in the conditional. So we say, show drawer toggle. If so, show the action button. And if not, we're going to get a false there. It's just going to render nothing. Jan says, is an iPad simulation available to test that? It is. Oh, and I saw I missed another question. So let me back up. Vicky says, FlexGap not available too. I don't know. I do remember wanting and missing FlexGap. Yeah, it looks like in
react Native Flexbox, I don't see a FlexGap property, unfortunately. So you might need to do similar workarounds to what we did on the web before FlexGap was available. All right. Jan asked, is an iPad simulation available to test? Is an iPad simulation available to test that? Yes, we should. I have not done this on my app. I don't know if I've done it ever, but we're going to do it live on the call because we have time. So yeah, let's save this and see this working and then we'll test it out. We'll find an iPad that has a size because they boot up pretty quickly in the simulator. So yeah, let's come back to that in just a second. This will be a fun experiment. I like to be put on the spot and I like it when things go wrong. People that watch my live streams do as well. All right. So let's take a look here. Custom navigation bar. We save. We see on this large screen size, the drawer is permanently available and the toggle button is not shown. Let's shrink down. Now the drawer is conditionally shown. It's toggleable and the toggle button is there. We can toggle it. And as soon... Well, watch this. When we see it, let's look at the point. As soon as we cross over that pixel point, as soon as the drawer is shown, the toggle button goes away. And as soon as it disappears, the toggle button shows. That's one of the reasons to put your breakpoint logic and the sizes in one place in the code base. That way, those don't get mismatched and you don't experiment. Oh, let me see what the width needs to be and you hard code another value there and they get out of sync. You wouldn't want to get to the point where the drawer was hidden but the toggle wasn't yet shown. You want it to cross over. That's two conditions. You want to code to that specific breakpoint. And so using this code this way really helps with that. Demetri says, you have live streams. I would be interested to watch. It's on YouTube. Thank you. Yes. So I'm pausing on my live streams at the moment but there are recordings. Those are available. They're linked on the conference web page. Sorry, maybe the conference web. It's the workshop web page. They're linked from there. I'll show you real quick on here. If you go to Coding at Live, Coding at Live is the name of the website, the links to my streams. It is on Twitch. I need to update. It's all updated right after this to say that they're on pause right now. But the past recordings are all available. And so on a lot of these streams, I've been talking about Shirley as a
react Native web application for web and mobile. I actually built out a second application using the same approach called Firehose. It's a link saving application. And so if you want to walk through a process of seeing an app being built using
react Native web and Expo from scratch, those are available on my YouTube channel there. So yeah, if you go to Coding at Live, you can see some more there. I also like to talk about
testing a lot. And so
react Native
testing is another topic I hit upon a lot. And so you can stay in touch with me there. As well as on codingwrong.com is where my social media, blog posts, and other ways to stay in touch with me. So cool. All right. It is now time to be challenged and to do something live I hadn't tested before. And we're going to try out an iPad in the simulator here to see if things work the way I've so confidently told you that things work great on the iPad and that you asked to see it. So let's see it. Let's take a look here. Let's try iPad 10th generation to start. And as iPads have changed, I'm not rich. And so I do not have all the iPads like some of you might. And so I haven't seen exactly what the breakpoints are for different iPad sizes to see how the breakpoints will work out. I have thought about it. If I had any customers for this Shirley app, I probably would have bought an iPad to be able to test the experience for them. So I've opened this. And let's close this. I forget how exactly Expo tells what to open on the simulator. But I think if I have one simulator open and I press I here, I think it's going to load it up. So let's do that. Let's see if it works. Opening on iOS. Yeah, opening on iPad 10th generation. Just as a minor note about Expo, you see here that it says downloading the Expo Go app. The way that Expo works by default, and there's other options as well, is that you just write the
javascript code and they have a pre-built mobile application,
react Native application that has all the native code. Expo actually allows you to develop, even if you don't have a Mac, you can develop apps that run on the Mac because you don't need the simulator. You can just have Expo's pre-built iOS application, which is nice. All right, we're going to open up our app on the iPad. I kind of hope there is a bug because that would be fun because I like to be embarrassed and also it'd be something fun to work through. All right, so our app has opened up just fine. And we see that on this screen size, these are draggable to see. So I don't actually know how big physically an iPad 10th generation is. But we can see pixel size wide that it's decided that even a portrait mode on this iPad, it's wide enough that you can have this sidebar permanently there. And certainly if we rotate the iPad, that's wide enough. We can see that there's space for the columns there on left and right. So this is interesting actually, based on the max width approach that I took, on this screen size where the sidebar is permanently there, and it's pretty wide, honestly. In my, in Shirley, I think I shrunk the size of the sidebar because like, I mean, this text is very narrow, then sidebar doesn't need to be that wide. But so here we're less than that 600 pixel, 640 pixel max width there. So we don't have a gutter on the left and right-hand side, but that actually works out pretty well. This looks good on the size iPad. Vicki says, what's also nice with Expo, you can kind of deploy and give your future users to try the app out without even publishing in the app store. That is a really great thing about the Expo flow as well. I agree, Vicki. It's a lot of fun. Okay, so this iPad, I want to find an iPad that in portrait mode, we actually collapse down the sidebar. So let's experiment some more and see if we can find one. There's just so many of them. iPad Air, maybe? Let's try iPad Mini, sixth generation. If it gets small enough, it might actually be a collapsible sidebar on all the sizes. So let's try this and find out. Yeah, with Expo, basically, because you can download the Expo Go app from the app store, people can just download that app. And you don't need to set them up as testers that you sent them a built iOS application. So that makes that a little bit easier. I don't know if I'm summarizing it well. Vicki might be able to summarize better. But yeah, Expo is a great tool. If you haven't built on
react Native yet, definitely check it out. And again, if you want
react Native web, Expo is the recommended way to do it. All right, well, so it looks like on the iPad Mini, in this case, even on this size, it's collapsing, it's showing the sidebar permanently. Let me tweak the values here so we can see when it collapses down. And that might be enough to show. Luckily, I got embarrassed. That's good, not actually embarrassed. If we change the breakpoint large size, and there's probably, I'm sure there's websites where you can see screen sizes of different Apple devices. Let's say 700. Yeah, that's not big enough, 800. There we go, okay. So when I go to the iPad Mini, there we go, okay. So when I set the breakpoint large to 800, this shows us that on our iPad Mini, in portrait mode, we are actually able to toggle the sidebar. So we toggle it out. And let's see what happens when we rotate. When we rotate, we actually get the sidebar popping out, and it's consistently available there, and we no longer have the toggle. So that's pretty cool. And let's even try when we have it manually toggled out. We rotate, it's there unconditionally. We rotate there, now it's there conditionally. So this feels cool. I mean, this feels like a real mobile app with a lot of a rich functionality and a nice look and feel. Yeah, I just like this responsive
design. I think, you know what it was? I think 600. Actually, one of the things I tried to think about when I was thinking about the sizing for my app was, I think for some of the really large phones, they're actually large enough so that in portrait, in landscape mode, the sidebar is unconditionally shown. You might or might not want that. So you might need to toggle your responsive settings to really fit. But let's try the iPhone 14 Pro Max. Let's just get the largest resolution. I don't keep up with Apple News, so I don't know exactly about the sizes. Why is there a Pro? Why is there a Pro Max? I'm not actually sure. And it seemed like when I was
testing, the sizes were somewhat similar. But let's see what happens with the Pro Max. If you are building for iPhone, one of the nice things about having a Mac is that you can run all these simulators locally and try all these things. But there's hosted tools that give you options as well. So on the Pro Max, no matter how huge this phone is, it's still small enough that our sidebar is toggleable there. Let's rotate it and let's see. Oh, actually, there's a setting. So yeah, there is a... This is a fun experiment together. So in Expo, there's a setting here that lets you change the portrait. So right now, the app is fixed to only work in portrait mode on mobile. On iPad, clearly, you can rotate it anywhere. We have time because we're not in a rush. Let's check the Expo docs here and let's find the setting to allow it to rotate. This is all very on target because we're not tight for time for three hours. Orientation. No, I want config. I want app.json. There we go. Properties. Orientation. Default portrait and landscape. Logs your app to a specific orientation with portrait and landscape. Value values is default. Okay, so we want orientation default. So let's try that. Let's... I'm going to reload to make sure. And now, let's see if we can rotate. Remember, this is iPhone Pro Max, which should be, hopefully, a pretty big phone. Yeah, so check that out. There was a little bit of visual issue there, I think. I mean, probably you can rotate it fast enough. Yeah, there we go. So I rotated it fast enough. There was a bit of a timing issue. So that'd probably be good to
debug. But yeah, on an iPhone Pro Max, full size. A phone is just one size. On an iPhone 14 Pro Max, with my breakpoints the way I have it set up, landscape mode is wide enough that the sidebar permanently shows. Now, you see I have some safe area issues here, where the drawer here automatically handles the safe area. So if you rotate in this direction, your navigation items don't overlap on this floating notch, whatever it's called. And this orientation of the phone works fine. But if I rotated this direction, this button is all the way over here. So this content would overlap this notch. So
react Native has good safe area code approaches. And so there's components you could put in there that would keep this part of your screen safe there. This is one of the reasons that if you're targeting all the iPhone devices, all the Android devices, and all web devices, there's a lot of things to cover. You're going to need to test out, I mean, test on web on iPhone 14 Pro Max as well, and make sure that it doesn't go into this, that your content stays in a safe area as well. So this
react Native web doesn't solve the work that's needed to, all the work that's needed to target all these different platforms. You want to test to make sure things are good. What it does is it allows you not to have to build from scratch, and allows you not to have to learn three different ways to identify safe areas. You can use
react Native's abstraction for safe areas, and your app is going to be able to cover them in all these cases. All right, chat says, have you ever used some other UI component libraries, Vicky says? Maybe there's some specific components you can recommend. View to slide out from the bottom. I'm not sure if paper has it. I'm not sure if it has that as well. I remember another
component library that I use is
react Native Elements. That's another one that's been around for a long time, has a lot of really basic useful components. It's not based on any particular style, like material
design. And I think it can tend to be closer, in some cases, to what's default on iOS. At least for me as an iOS user, it feels closer, like ListViews and things like that. I don't know if it fits what's natural for Android. It might or it might not. It might have different components that are more natural for iOS or for Android. And I know that I've heard really good things about
react Native Elements for years. I'm sure there's others. There's others, even some of them that are lower level things. Like I said, I know I've heard some of the folks that have been on my live streams have talked about different
design libraries. Unfortunately, I don't have too many recommendations myself. But if you get into the chat here at the conference or other
react Native communities online, folks will have recommendations on that. So cool. That was some fun experimentation on this responsive
design here. And I was able to prove out, thankfully, yes, that this responsive
design does, in fact, work on iPads. I don't have an Android tablet. So I don't have that up in the emulator. So I'm not sure if that will work. But it sure seems like it will. And if there's a bug, I'm sure you can work around it. All right. That was a great rabbit trail down into responsive
design. But remember where we're at. Where we're at is we now have this nice permanent sidebar that stays out if we have a large screen size. And I can surely leave my to-do list. I use all day every day. I literally live out of my to-do list because that's just the way I'm wired. And so I've got it up in a web browser with my sidebar permanent. And I've got it on my phone where I pull up. And so I use this every day. Carola says, do we need to look at some kind of specific compatibility notes of Libs to work on mobile and web? Yes, you do. That's a great question. So I haven't tested extensively. Clearly, these
react Native
web apps that I've made are pretty basic in functionality. But you will want to see in the reading of these libraries, does it work on the web? And certainly, if you're looking to make a
react Native web project, you're going to want to say from the start, what are the essentials? If I have a map-based application, then before I do anything else, I want to get the map running on web and on mobile to make sure that it's going to work great before I build everything out. Now, when we get to the, which I think is coming right after this actually, we talk about platform-specific functionality. Even in a worst-case scenario, say you have a library and you're like, this just doesn't work on web. It only works on mobile. You may need to implement yourself on web or you may need to find an alternative on the web. Maybe you can contribute to the
react Native library to give it better web support. That could be cool. But not everybody has the capacity for that. I have not done that before. So what you can do in your app is have conditional code where for the web, you have conditionals around it. You say, on the web, load this map library. On mobile, load that map library. And that can be a way that you can handle it. But that's actually a great transition into what we're doing next. So let's keep going. And we haven't been going for too long right now. This is going to be the home stretch as far as platform-specific functionality in our
react Native web app. After that, we're going to do a very brief wrap-up where I talk about considering how I would recommend you think about whether to use
react Native web or whether to use separate
react Native and
react web applications. So let's dive into platform-specific functionality. For this, I don't have examples in this code here. But what I do have is the Shirley code base. So I'm going to pull up Shirley, my to-do list app. And we're going to take a look at it there. And I do want to show you the app first so you can see the conditional stuff we're going to be looking at. So this is Shirley. It should look very familiar to you. Here's my sidebar. I got little icons added in. That was kind of fun. You can see my centered column over there. But I've got these to-do items here. I can add in to-do items. I can click on them. I get a little detailed screen. I'm on the child screen with a URL where I can go back. And I can edit my to-do's. I work in this all day. Oh, a little visual issue there. That's interesting. Oh, nothing's perfect. All right. So in Shirley here, let's take a look. Oh, and I want to show you on mobile as well. Let me pull up my actual phone. So I have my physical phone hooked up to my computer. Here's the
video feed coming over from it. And so this is Shirley, the native application running on my phone. And I'm tapping over there. So let's look at the sidebar. So in the sidebar here, you can see over here on the web, I have a download on the App Store button. Because that's nice. If someone's using Shirley on the web, I want them to know that it's available on the App Store. Now, not if you're on a phone, because if you're on a phone on the web, I want them to know as well. But if you're in the native mobile app, I don't need to have the download on the App Store button. They already have the app. They're in the app. So that's a conditional. This content could display on both, but I conditionally want to display it only when we're on the web. So let's take a look at how I did that. We'll pull it up here. Yeah, here is the Shirley code. So this is the navigation drawer. So here, and again, this is the first time I built it. And then I extracted the content of a workshop out of this application. So a lot of this should look familiar. And so check out what I have here. From
react Native, I'm pulling in this
api called platform. And then up here, I say platform.os, and I compare it to web. So this is a platformer's functionality built into
react Native. It allows you, you can actually check iOS or Android on there. But when you're using
react Native web, web is an option as well. And because I like to create tiny little variables and stuff like that, I just create an is web constant that's true or false, depending on if this matches. Well, let's see where that's used. And down here in the drawer, I just say, if it is the web, then show the download on the App Store button. And that's pretty much it. It's just a conditional where we detect the platform that we're on, and we either show it or don't show it, depending on the platform that we're on. So there's one change. And this is something you could think about. Just because your app is available on web and on mobile, it doesn't need to be identical. So maybe you have something that's easy to add on mobile, but maybe it's just not possible on the web. Or maybe it's hard. Maybe it's going to take you some work. And you would like to make it available to your users on mobile, and then you'll see if you get to it on the web. You can add a conditional around it. You can add a little placeholder that says, I mean, in this case, it's a button. You don't need to, but it's like, hey, if you would like this functionality, download the mobile web app. Please don't ever do that, though. One of the nice things about
react Native web is you can have an awesome website and mobile sites. You don't need to do that thing where you tell people it's better in the app. Like the website and mobile app are both great, and both work really well. So this is one approach to different platform-specific functionality is by having just conditionals around there. Let's look for other examples in Shirley. Let's go to the About screen. I'm going to go back from here. Oh, wow, something interesting is going on. Yeah, About screen. Pull it up. All right, so here's the About screen on web and on mobile. What do we got? Made by me, get support, ways to say thanks, Shirley web. So you see this is kind of going back in the opposite direction. So when you're in the mobile app, I link you over to the website, just so you know that that's available as well. When you're on the website, I don't need to do that. So that's another conditional. Let's take a look at that. And then I'll get to that question in the chat. Again, I check Platform OS equals web. And then I say, oh, if we're not on web, show the button that goes over to the web. Let me look on chat here. Vicky says, from your experiences, it makes sense to try to cover the web version of the app using
react Native, or is it better to have a separate implementation? To the same topic, have you ever experienced issues where you could not achieve what you wanted in either iOS or Android? The separate web version, I'm going to come to that shortly in the wrap up for the workshop. So I'll come back to that one. But feel free to ask a question again if I don't fully cover it at that time. Have you ever experienced issues where you could not achieve what you wanted in either iOS or Android? In the apps that I've worked on, I haven't run across that. I've certainly run across differences. When I was doing styles from scratch in a recent
react Native professional consulting application, it was so interesting. I got a
design with a drop shadow for an element, like great shadows. And then I found like, oh, wow, when you're coding this from scratch, the way shadows work on iOS and Android in
react Native is very different. And so that was a lot of working around that and a lot of back and forth for the designer to say, oh, here are the constraints of these different platforms. So there can definitely be work across the platforms. One of the nice things about a library like
react Native Paper is they already have those things working on both platforms. Generally for
react Native, a lot of functionality targets both. I mean, if you have something that's very specific to one platform or the other, like something that only exists on iPhones, then there might be a library that's specific to that and you might need to put a conditional in that place. But I haven't written apps that very specifically integrate with those very low level things. Generally, there's a lot of really great
react Native open source libraries that wrap over those iOS and Android differences. So iOS and Android differences, I haven't run into cases where I couldn't achieve what I wanted to across both of those. And again, for your other question about web, we'll come back to that shortly in the wrap-up. All right, so now let's take a look at some other conditionality here across platforms. Let's go to the Ways to Say Thanks screen. And go into here. So this is, again, sure, free app. I'm not trying to plug my app. You can use it if you like, if you wanted to do this. But it's very low features because that's what I wanted. Anyways, so the first button here is Share with Friends. And so let's see what the options are. So on mobile, when I tap on Share with Friends, I get that built-in iOS share sheet. So that's pretty nice. Actually, interestingly, on the web, I just pulled up Safari here, which I barely ever use. But on the web, on desktop, when I say Share with Friends, a little share interface pops up in here as well with all my family members with their full names. That's fun. That's okay. So this is actually a web share interface. This is an
api in some browsers. And I haven't checked browser compatibility recently. But I believe in Firefox, that's not the case. So when I click on Share with Friends, it just takes me to the Shirley URL just to give you a URL to be able to share. So that is not available in Firefox currently. I haven't tested in Chrome. So let's see how that works. So there's a share
api on mobile and in some web cases, but not in other web cases. What do we do in that case? Let's find it here. So here's my Share button. Share with Friends. And I created a Handle Share function because there's always some way to share. It's just how it happens differently. So under Handle Share here, I have Is Share Supported? And I say, if that is supported, then call this Share
api, which comes out of
react Native. That's built into
react Native, interestingly. But if Share is not supported, then I just open the URL using this linking
api, which is also available in
react Native. That just opens a web URL. So how do I identify if Share is supported? So it would be nice if the share.share library always worked. If there was a way for it to always work, that would be great. I don't need a conditional. Or sometimes we'll see down below here in a second, sometimes a library will tell you if it's supported on a platform or not. In the case of Share here, it did not actually tell me. So I didn't need to do my own logic. So what I had to do was just by experimentation on different platforms, I needed to find out if Share is supported. So what I found was if we're not on the web, Share is always supported. There is an iOS Share
api. There is an Android Share
api. So we're good. What about if we are on the web? We are on the web. We need to do, I think it's called feature sniffing. It's a web approach where you just basically check and see is that
api available. So I say if navigator.share is available, then Share is supported. So this is interesting. Notice I don't need to use navigator.share directly. If it is supported, I just call share.share. But if navigator.share isn't available, it just blows up. So unfortunately, the
react Native library isn't checking that for me. I need to do my own cautious check before I'm willing to call it. So what I found is that this is the condition I needed to know if it was safe to call share.share, which is basically when it blew up, I found what I needed to check. I can't just always check navigator.share because navigator is a web browser thing. It goes all the way back to Netscape Navigator for you old timers like me. So if I'm not on the web, I don't need to check that. I just need to know I'm not on the web. I'm good to go. So this is an example of a more sophisticated condition you might need to do and have a fallback approach. That's not quite as good, but at least gives users something rather than nothing. Let's take a look for another approach here, another case of a conditionality. So I'm going to keep unlocking my phone screen here. You see, I have this rate or review the app button, but it doesn't show up on the web. Let's see what happened. I think actually, I think I broke this. So yeah, this is not currently working. So I don't need to investigate that to see. But I can tell you what I was doing. And I know I've seen it work at least once. So there is a store review
api. This actually comes from an expo package, expo store review. And what that allows you to do is to send users to the App Store or Google Play Store so they can write a review for your app. This might be why my app doesn't have any reviews in the App Store currently. And so you can call that. In this case, store review actually has a function you could call to see is it available. If await store review that has action, call store review that request review. So this is a function in the store review library where it will tell you, yes, I can send the user to a review. It seems to be imperfect here. So part of it is if you're on the web versus not on the web. Actually, this is interesting. I'm remembering here. It's kind of interesting that the button is not showing up. So handle review. Yeah. Oh, so check it out. I have two levels of conditions here. So it's only if I'm not on the web that I show the rate or review the app. I felt like it was kind of tacky being on the web interface to ask people to rate or review the app. And it would even make sense. How do I know whether you have iOS or Android? I don't need reviews that bad. Probably I should just let you. And again, I don't have an Android app built yet, but the possibility in the future. So I don't want to send people from the web to the app store to review. So I just hide it entirely. But then I found also there was some conditionality here. And actually, store review encourage you to always check has action before you call request review. There's configuration. And this may be what I messed up. In the configuration for your app, you need to say, here is the URL of the app or the ID in the app store in the Google Play Store. And that's what allows store review to know where to send the user. And so it's only in the case that that's there that this returns true, resolves to true asynchronously. And then you can call request review. So that was a lot of details specific to store review. But my point on this is that you may be using a library where you can ask the library itself, are you supported? And if it tells you yes, then you're good to go. But we saw in a contrasting example, maybe the library will let you call it and it will just blow up. In which case, you may need to add your own conditional check around it instead. So these are some of the different scenarios you can run across. Jan says, you have hard-coded text in your app. How does
internationalization work in
react Native? Yeah, let's take a look at that because I finished the other train of thought. The
react Native apps I've worked on have not had an
internationalization requirement. It's something we raised because we know that's important. In the last consulting project,
react Native project that I had, and they decided specifically they were a real estate company focused in the US. And so they decided at the time it wasn't strategic to put the time into
internationalization, either on their web app or on their
react Native app. Let's take a look and see. ECMAScript
internationalization api. Basically, honestly, what it comes down to is I would check the
react Native docs to find out about
internationalization on
react Native. I know it's available. I think it looks like it probably uses basic ECMAScript APIs. I imagine IATnext is probably available because it's a very common library. And I know we're using it on the
react web application that I'm building right now. So I do not know as far as
internationalization, but I know it's available for sure because there's a lot of
react Native apps that use that. Cool. The last thing that I'll mention is there may be some cases where there's architectural differences between the platforms. And this would be an example of something that's just not available, and you just have to do it in a different way on the web. So let me show you an example of that because this is important to know about because this can affect your architectural planning. Expo Secure Store. Expo Secure Store provides a way to encrypt and securely store key value pairs locally on the device. And they tell you what underlying technologies are used for that. And so this, if you have credentials, including an access token or refresh tokens, a secure store is very important to use that on mobile to store it. Because there are other
data storage ways for
data that doesn't need to be secure like that. Those are built in sandboxing in mobile. So any app can't just reach over willy-nilly to another app to get its
data, but it's not safe enough for credentials. And so you want to use Expo Secure Store. Or if you're not using Expo, I think
react Native Keychain is the name of a library that's very well thought of and used for that. And so that's what I use in my app here on iOS for logging in. When you log in, you have an access token that's stored in Expo Secure Store. So this is not available on the web. So what do you do on the web? So the most important thing when it comes to
security is to understand why. So the reason Expo Secure Store and similar technologies are not on the web is that there is no equivalent for secure storage in web browsers. This is very important. I did research on this in a research week a couple of years ago because I really wanted to deeply understand this across all these different platforms. Architecturally, there is not a way to store this information securely in a browser that's encrypted and protected like that. And so you can't do it. You cannot do the same thing. This opens a real can of worms. And so it's like, well, what should you do? I certainly can't explain it very well off the cuff. And I haven't actually published this because I'm not a
security expert and I'm not a lawyer and I don't want to be held accountable if I say something the wrong way and your company builds something and gets exploited. So when it comes to front-end
react applications or
react Native web applications running the web, you need to do research on
security there. I will say, what I'm comfortable saying is that browser cookies are more secure. There are downsides there. There's things you need to mitigate there as well. But generally, so the thing that I would not advise, but people do do this, is to use browser local storage to store an access token. This is common. There's a lot of resources online that teach that, but it's not secure. It's not safe. I mean, it's not let me not mitigate that too much. That is not recommended as a way to securely store things. I will say, I'm not going to show you the code. I have a big comment disclaimer in this open source code that you can see if you go into it. So how do I store the
authentication in the app? Well, for a to-do list app like this, I do store it with local storage, but I do not recommend that. It's only because this is a trivial side project just for to-dos that I store that that way. I feel like the risk level is low enough, but I'm not advising you to use local storage in your own
react web application or
react Native web application. It is much better to use cookies, but look into the limitations of cookies as well. So on the web, you would need to approach things with a different
architecture, like there's not just a secure storage
api you could use. You might need to host it, your
react Native web app, through a server-side framework. I know there are ways to get expo with web to work with
next.js, for example, if you're using
next.js. So the point is there is a can of worms. This is a great example of a platform difference where it's like, there are no easy options on the web, and you're going to need to take some time into it, and you need to really think hard about the
security factors there. And my app is not an example. Do not use my app as an example for how to store credentials, and I have that disclaimer in that file as well. So I apologize I don't have simple, easy answers there, but it's life of a web developer. Web has a lot of benefits, but that's something we need to look into as a trade-off. Cool. Okay, so hopefully that makes sense. I'm going to check the notes here. It says some storage is used, though. HTTP-only cookies for tokens will work. It also has drawbacks. Look up OWASP guides to store JWT. I would agree with Carolice there. I'm not fully shooting down anything that was shared in chat there, but all the approaches have drawbacks. Yeah, and I do recommend looking up OWASP guides or other guides about token storage. There's great resources from Auth0 and Okta on token storage recommendations. There's even things about using
web workers and service workers, and a guy that I was at the last client I was at had done that before, but actually I couldn't find any examples online of how to use
web workers and service workers to more securely store tokens. Maybe other people that don't want to put their information out there and be at risk of liability. So yeah,
security on the web for client rendered stuff is a challenge for sure. So thank you all for sharing some thoughts in the chat there. I will say, a client project that I was on, I chose local storage for storing the tokens, and then afterwards I was like, oh, I found out that's not good. And so I raised it to their
security organization. I said, my bad, there are downsides here. I cannot choose for you. You as an organization need to decide what to do. And we did a really
deep dive into
security. They thought through it and their organization made a choice about what to do. And I won't share the details because that's confidential. But so I had done something that as a consultant afterwards, I was like, I wasn't secure enough. And so I went to them to raise it to them so that we all together could work together to decide what was the right thing for their
security profile. Okay, that was a real
deep dive on
security there. But if you got nervous about web token
security, then mission accomplished. I'm glad that you are. Now don't feel bad. That's why I said that I made a mistake on this and I felt that afterwards. Maybe I shouldn't phrase it that way. We are all growing and learning. And so learn what you can at the time. Do what you can to make things as secure as you can. Raise trade-offs to your organization so that organization leadership can decide. But as a professional,
security is so important. In the last 10 years have shown us anything in software development is that we need to be more secure. And so I would recommend looking into secure token storage on the web and on mobile. We can all do to level up our
security knowledge. So it is a investment well spent and just I personally believe ethically is just so important. And it serves your organization, your employer as well, and your user as well, maybe most importantly. Okay, let's come way back from that
security thing. And let's go to the wrap up phase. And then after that, I can stay on for questions if anybody has anything you'd like to ask about. But I'll point you to places that we can stay in touch. Thank you for exploring all this code with me. So we've seen
react Native Web in use now. If it was unclear what it even is, hopefully it's very clear now. Or at least what it could be, what you might want to investigate in the future. So when would you want to use it? And this goes back to a question that was asked earlier, I think by Vicky. Okay,
react Native Web is an option. Should you always use that instead of normal
react for the web? If you've got a
react Native app, like is there ever a case where you'd want a
react Native app and a separate
react Web app? I think there is. I think there's trade-offs to choose between the two. So let's talk about it together. And I would love to hear if anyone wants to share in the chat after this. I would love to hear your thoughts on the trade-offs as well. And certainly I would say, I mean, the most important thing is if you're looking to start a project with a new
react and
react Native, investigate. Check it out to see if you'd like to use
react Native Web or if it's better to use it separately. You might go either way and ask the
community. The
react Native
community would be happy to chime in. I'd certainly be happy to share my thoughts as well. Yeah. So here's my thoughts. So certainly, I mean, maybe the most obvious point is I would use
react Native Web if you need both a web and a mobile app. But the reason I bring this up is you might not need both. You might think, oh,
react Native Web exists. I might as well get a web app and a mobile app. But we've seen some of the challenges. It's not free to have a web app version of your mobile app.
security is a challenge. And
testing things on different iPhone screen sizes, different Android device sizes, there's work involved. There are downsides. And so if you're, I mean, there are places and areas where mobile app only is fine or web only is fine and that gives you everything you need. And so there will always be a cost to supporting both platforms. And so
react Native Web doesn't give you that for free. So think about do you need both? You might only need web. You might only need mobile. Or at least for this stage of your organization or your business, you might only need one. But if you do need both web and a mobile app, I would say if it's largely the same app on mobile and on web, that's a good reason to use
react Native Web. If it's largely different, maybe not. Some cases I can share are, one of my first contracts in consulting was for an app where the native app was for end users. It was through a hospital system. And the web app was for hospital administrators. So it was different audiences. And so there was very different, I mean, same
backend data, but it was very different use cases. So they didn't need to look the same. They did not, you know, features by default did not get added to both. If anything, it was a very different way of looking at the same
data. And so
react Native Web would not have provided any benefit here because it's entirely different screens for entirely different users on mobile and on web. They should be built separately. Now Shirley is a great example of it's the same to do list app. I want it to look almost exactly the same. 99% of the UI and functionality is identical. A lot of benefit to
react Native Web. I was talking on the Infinite Red podcast through Infinite Red. And one of the developers, Robin, shared about how she had done a
react Native Web application. And she actually had, it was, there were some screens and functionality that was fairly different across mobile and across web. And, but she found like, no, yeah,
react Native Web still provided a lot of benefits because there was a lot of screens that were the same. So there would be more conditionals in that case, you know, render out this screen versus that screen on the different platforms. But I pass along her recommendation for you that, like, even if it's largely the same on mobile and on web, you can still find a benefit from
react Native Web versus having to re-implement them from scratch. The other thing I should say, and we didn't get into this in detail, is use
react Native Web if you don't need fine-grained control of
html. So when you're coding
html directly, even using
react, where your JS act is outputting individual
html elements, there's, you know, you choose, like, okay, what semantic elements am I using? Am I using header and main and aside correctly? All of the
accessibility attributes and things like that. Is it a button? It looks like a button, but it's really a link. So I should use an anchor tag, but style it. All those different concerns for the sake of semantic
html and for the sake of
accessibility. So that's the mindset when you're coding for the web, including
react for the web. For
react Native Web, it's an abstraction over those details. And so you don't get access to them. And so if you're going to feel frustrated by that, maybe it's not going to work. Or if your app requires you to have access to that, that's not going to work. One example, I noticed that a pressable, at least at one point in time when I checked it, the pressable component for
react Native, and
react Native Web was not implemented as a button. It was implemented as a div that had the right ARIA attributes to make it indicate as a button and stuff like that. And if you know about
accessibility on the web or semantic
html, you would say, no, that needs to be a button. You should not prefer a div with ARIA attributes. You should prefer a button. So there was an open GitHub issue about that. And the reason it was implemented that way in
react Native Web is there was a visual issue in some environment, I forget, where a button was causing a problem. So this is one of the things where when you're coding
html and you're coding one specific element on one specific screen, you can use button. Great. You're good to go. But
react Native Web is translating every pressable and every
react Native Web application in the universe into
html. And so for them, if there's some cases where a button won't work because there's a bug in some browser, they can't use it. Or maybe they can make it conditional or something like that. I think they were planning on that at some point. So when you're working through an abstraction like
react Native Web, you can't access the
html as directly. You can contribute to it. And so you could find like, oh, I want to improve the
accessibility here or the semantic
html there. And you can help contribute to
react Native Web. It's an open source project. That would be really appreciated. I would appreciate it. I got my
react Native Web app. But so that's something to think about. Like for your needs, I think everybody should prioritize
accessibility in their applications. But for your needs of your app or your business, your organization, do you need that fine-grained control of
html? Is it going to really get in your way to be running through the
react Native Web abstraction? So think about that. Maybe do a proof of concept. Maybe build one screen in
react Native Web and see and try to get it fully accessible, fully semantic to your
standards for what you need your web app to be like and see if
react Native Web will get you there. And you may find that, you know what? It's worth the cost for us to maintain a separate
react Web application because we get full control of the
html. At that point, you've made an intentional decision. You've decided, I got a
react Native app and I've got a
react Web app for a reason. And you know why you're taking on that extra cost. And in a lot of cases, it does make sense to do it. So those are my thoughts. But those are all things where I would say those are cases where you'd say why sometimes you might choose
react Native Web. And sometimes you might choose to have a separate
react Native and
react code base. And of course, any code that's not UI specific can be shared. So your business logic, your
data layer, custom hooks of many different kinds, third-party
javascript libraries, first-party internal
javascript libraries, those can be shared across
react and
react Native. So maybe that's the level of sharing that makes sense for your application, but it's a separate web UI from mobile UI. I see some thoughts in the chat here. Let me read this. Jan says, what do you prefer, an Electron app with
next.js or
react Native app? That's a great question because Electron is an option on the web. Well, so let me think about this. Electron, if I know correctly, I'm saying correctly, Electron is an option for desktop, laptop, Mac OS, Windows, Linux, to run an app. And you can run
next.js or some other
react app inside of it. Whereas
react Native runs on mobile. And oh, and
react Native runs on desktop as well. So Microsoft maintains
react Native for Windows and
react Native for Mac. I don't know about Linux. And you can easily add that into a
react Native application. So I don't know. I do know that personally for me, I use a lot of
react Electron applications and they're good enough for me on the web. I haven't tried to add
react Native Mac functionality to Shirley. I just use the Shirley web interface and actually use a little command line tool that creates a really trivial Electron app that wraps the
react Native web interface. So yeah, I don't think Electron runs on mobile. And so maybe probably that's not what you're asking about. But so on mobile, I would use
react Native. I haven't used any of the other
ionic or other kind of web wrappers on mobile, but they tend to not have a favorable opinion amongst mobile developers.
react Native tends to have a more favorable opinion. On desktop, web-based things tend to be fine for my purposes. And so Electron or just
web apps tend to work for me personally. See, someone said that session storage is the recommendation. I will say that I've seen downsides to session storage as well for token storage. So I personally am not saying session storage is obviously a totally fine for use. I can't describe it too well off the top of my head, but I just encourage folks to keep investigating. Yeah, as Corolla said, session storage alone is vulnerable. Again, some more things about
security. I'll skip over those. Styling is not that powerful in
react Native as it is in
css. So I often find myself struggling with this. Absolutely. That totally makes sense.
css isn't brought over automatically and not everything is in there. The reason there's a number of, well, I mean, there's a ton of styling libraries on the web as well. But one of the reasons there's so many styling libraries on
react Native is to work around built-in limitations or rather to say, again,
react Native is creating a universe from scratch. Like they're building another levels of abstraction with additional functionality on top of it. But styling is a challenge on
react Native. And I talked about the issue I had with shadows. Just getting a shadow is challenging because Android and iOS have very different concepts. And
react Native uses the native functionality under the hood. And so they are building with what iOS and Android gives them, which isn't always identical. Yes.
security on the web is hard. That's why Josh is not comfortable on telling us what, how to do. Absolutely. Go find those folks that are
security researchers that have the legal protection and the insurance to be able to make recommendations and are more informed than me to be able to make recommendations or hire me from a project. And then I'll give you recommendations with qualifications appropriately. Jan says, Electron is running on mobile as well. I did not realize that. That is very cool to hear about. And I might be more likely to reach for that than something like
ionic. So I'm going to write a to-do and surely literally check out Electron on mobile because I want to learn about that. I haven't reached for it before, but I like to know these options that are out there for folks, certainly when folks ask questions. So I appreciate Jan you sharing that as well as all the other stuff that folks have been sharing together today. That's cool. All right. Yeah. If anyone else has thoughts on when you might use
react Native web versus separate
react on the web, definitely feel free to share that in the chat or in Discord. Jan said, I never was in touch with
react Native before, but you fixed me on it. Thank you very much for this great workshop. You're very welcome. I hope others have gotten benefits here as well.
react Native is different than the web. And so, and yet there's a lot of overlap. And certainly when you're in, and I guess this is another positive side, in general, this is what I say about
react Native organizations. If you're using
react already, there's so much about
react Native that is so great and so much that carries over the mental model, the programming model, so much shared code, even if you're not using
react Native web. So any organization, I mean, honestly, as I thought in consulting, work at the last place I worked at a lot of native mobile development as well as
react Native. So when do we recommend which? The simplest thing I came down to was the best case for using
react Native is if you already have
react developers and you don't yet have a mobile app and
react Native would fit your use cases, consider
react Native.
react Native web is a great use case for if you don't yet have a web or mobile app and you want to build for both at the same time, reaching for
react Native web could be a great option in that case. Coral has asked for a concrete link on electron mobile. So yes, please do share that if you have that and I'll Google it. And if I find it as well, I mean, I imagine Jan will share that link if it's available, but I'll share in Discord as well afterwards. Keanu asked to Expo or not to Expo or maybe any case we should eject. So I haven't, I've used Expo only on side projects, not on professional projects. So I can't speak to that too strongly. I know the folks at Infinite Red, which is extremely experienced
react Native consultancy, they use Expo by default. And one of the great things about Expo is I've shown the case here where we're just writing
javascript code, but Expo does have ways in the last couple of years where you can build in native code, where people can create config plugins so that native code can be added in. And so that way you're not custom tweaking iOS files and Android files and things like that. So that is an option with Expo and there is still an option to eject out of Expo as well. So there are others out there who have better knowledge than me about Expo versus
react Native CLI. So I'll defer to them. Okay. Let me see what else I have. We are still in wrap up, but only a little bit left. Conclusion. So this is a big picture thing about abstractions. Why did I work like this for surely? Why did I look into
react Native Web and what drew me to it? So a lot of folks in software development are focused on doing more. Like what is the latest and greatest thing? What's new APIs? What's new technologies? Chat GPT just came out this week. That's mind blowing and exciting and worrying. That's all I'll say about that. But people doing things that have never been done before. And some people do that. I'm really glad they do. People invent new UI
frameworks like
react or new
javascript build systems. That's really neat. I'm glad people do that and I like benefiting from their work. But doing more is not the thing that gets me the most excited in software development. For me personally, what gets me more excited is doing more with less. I love abstractions that allow us to me as a consultant and when I've worked at companies and people working at companies, just let me build the feature I want to build. And if you can take care of any of those accidental complexity as the technical term, any of those things that I don't want to have to worry about, just let me get right to building the feature for my users that I need. That's beneficial. And
react Native totally falls in that category. It's a lot of work to learn iOS and Android separately and build the same thing in both. Or it's a lot of money for a company to hire experienced people that know both of those and a lot of coordination to give the same feature added to both of them. That's a lot of things that's not delivering the features to users. One of the great things about
react Native, and there's downsides as well, for sure there's trade-offs, but one of the great things about
react Native is it allows you to focus more on, let me just get those features to the users and can you make it just work on iOS and Android. And one of the great things about
react Native Web is it adds web into the mix as well. Trade-offs, of course, but it gives you an option to say, let me deliver features to iOS, Android, and Web and not have to worry about the implementation details and re-implementing something from scratch. That's what gets me excited about
react Native Web as well as tools like
react Navigation and
react Native Paper. Having the option to not have to build those things from scratch unless you need to, it works really great. To the degree that this is for you, if that's your wiring, if you are at a small organization, maybe a nonprofit organization, maybe you're an internal team and your whole job is not making an app, but maybe these abstractions let you build something that's useful and saves you work and is beneficial to your organization. I love tools and ideas that equip people to be able to do more with less. Maybe that's a fit for you. Maybe not today, but maybe sometime in the future. Again, to summarize, this is the webpage again that I sent you to at the start. It'll be in Discord afterwards as well. This is the workshop webpage that has a full write-up of everything we walked through as well as the starting and ending repo that you can download. If you don't want to code it all yourself, just download the ending repo and build your app off of that. It also has ways to keep in touch with me personally and with Test Double. Again, Test Double is the consultancy where I work. We work in
react Native,
react, and on the web as well, and a number of different web technologies. If you want to hear from us, you can sign up for testdouble.com slash newsletter. I've got some blog posts and some screencasts that I'm planning on working on in the new year to share with you there. Git Nation has a Discord server. I also have my own Discord server where I talk about
react and
react Native and
testing especially. This would be a good place if you want to stay in touch with me and with a number of other people that work in
react Native especially because that's what my livestream is on. There's a number of
react Native people in there chatting. That's a great place to stay in touch. That's linked from the webpage or from the slides if you get the slides later. You all have been asking so many questions in the chat already. I'm going to look down there, but we are done. Thank you so much for joining. Feel free to head out 15 minutes early if you want to or if you need to. I'm around for the next 15 minutes and for any questions you might have. Let me take a look at the chat. Jan found that it turns out Electron is not available for mobile after all. No worries there. There are tools I'm aware of.
ionic is the name of one tool that allows you to use web code.
react Native is
javascript, but it turns into native widgets. There is no web view. There's no browser view in
react Native. That's something important that not everyone knows about, but there are tools for building native mobile applications that do use web views.
ionic is one of them. Cordova and PhoneGap are another. I think they're the same thing, but one of them is open source and I think there might even be others. There are tools that let you have web views so that you are using DOM elements. I think when I've looked at them, they have other kinds of abstractions as well. I don't know if they allow you to just drop your
react application directly into a native mobile app. Others of you all might know more than me. I know that Cordova and PhoneGap are options. If you don't want to use
react Native, you want to be doing web web, there was a consulting project I ran across recently where the client was like, yeah, we have
react components and we want to use them on mobile. It's like, okay,
react Native won't work because those components are
web components running in DOM elements. In that case, I wasn't directly involved, but the consultants I worked with did advise, I think Cordova for that case, to be able to use those because they were not able to re-implement in
react Native. That wasn't a fit for their use case. Corolla says, thank you and see you tomorrow in
testing workshop. That's great. I'm glad that you'll be there. I'm excited about leading a workshop on
react web
testing tomorrow. I don't know if registrations are still open or if people's schedules are still open, but I'm looking forward to presenting that as well. Thanks for the thanks, everyone. I've really enjoyed it. There's been a lot of engagement in the chat, even you all answering each other's questions, and I really appreciate that as well. That's
react Native web. Try it out yourself or fork my code and build off of it and see what you think. Whatever your coding looks like in
react on the web and on
react Native, yeah, I hope it's helpful. Feel free to reach out at any time, email, LinkedIn, Discord, anything like that. I love chatting about these things. I'd be glad to help you out and field questions or put you in touch with people who have answers to the questions as well. Thank you all for joining. I've really, really enjoyed it and had a great time. Thanks. I'm not going to click close just yet. I'll just leave it another minute in case anybody asks anything. Feel free to head out, folks. Thanks so much. Cheers with my sparkling water. Many of you all may be in Europe. I don't know if this is a thing in Europe, but in the US, sparkling water has been a thing for a number of years. It's silly. I think sparkling water has much more been a thing in Europe. I didn't get to come to Berlin for the conference, unfortunately. I did get to come to London for
react advanced London. I was very excited about that. This year was my first visits to Europe. I got to go to Poland for
react Native EU. That was very fun. Then I got to go to London for
react advanced London. It was so cool. As your stereotypical American who has only been over in the Western hemisphere, it was just so neat to get to visit Europe. Everyone was so great. Folks in Poland were patient with me, not knowing Polish. I tried my best to account for things and to be helpful. It was just so neat to visit. I really, really hope to be involved with Get Nation conferences in the future to get to visit London again, maybe Berlin next year. Thank you for accommodating my time zone. I hope this time worked out okay for you all as well. Yeah, I can't wait for
react Abraham talks to go up. I'm looking forward to checking those out and seeing which ones I can learn from there. Thanks so much, everyone. I will be in Discord at least for the next week in the Get Nation Discord for any other follow-up questions you all have there. Thanks so much.