How to Add Hover and Focus States to a React Native Mac App
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
This lesson preview is part of the Building React Native Apps for Mac course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to Building React Native Apps for Mac, plus 70+ \newline books, guides and courses with the \newline Pro subscription.
[00:00 - 00:13] There are other details that make the desktop experience different from mobiles . Namely, we want to give the user more feedback whenever the mouse is used or whenever any element is highlighted.
[00:14 - 00:29] One of the things we need to take care of are hover states. Unfortunately, React Native macOS still doesn't have very support for many of the actions that you would expect, keyword events and hover states and other details.
[00:30 - 00:42] So, we're going to work around some of these issues by using undocumented APIs. This API is my change in the future, but they might also establish themselves.
[00:43 - 00:50] So we're just going to use them for now. So we're going to start by using hover states.
[00:51 - 01:05] I'm going to go into my button component. And inside of the button component, we have the touchable opacity component, right?
[01:06 - 01:22] And so this touchable opacity component has a few undocumented properties that we will take advantage of. One of them is the onMouseEnter prop, which takes a function.
[01:23 - 01:35] And I'm just going to do something like set is overt to true. The other function that we need is onMouseLeave.
[01:36 - 01:41] And I'm going to use this as false. So I need some internal state into my component, right?
[01:42 - 01:52] And to tell it, it's currently being hovered. So I'm going to use a hook for that.
[01:53 - 02:12] It's a simple, simple US state hook, and it's going to start as false. Now you can see because these are undocumented and they're not really part of React Native, of the pure types of React Native, that we're going to have to ignore the type error for now, right?
[02:13 - 02:18] We're just going to tell the TypeScript compiler, don't worry about it. We know it doesn't exist on the types.
[02:19 - 02:31] We're still going to use it. And then we're going to use our small trick that we did before to change our styles.
[02:32 - 02:42] Let me change this into our CW function. And what else do we need to change?
[02:43 - 02:47] Oops. This one, this one.
[02:48 - 02:56] And I'm just going to say to make my life a little bit easier. Let me think about this.
[02:57 - 03:08] So I'm going to change the font size is OK. So I'm going to say my font is VOTE whenever my button is hovered.
[03:09 - 03:27] So now if I go to my application and I hover over my button, you can see the font getting bold. Now this is not perfect because, like I said, React Native Maco has still not super polished around this event.
[03:28 - 03:45] So for example, if I would have another element on top of my button, it would still trigger the on hover state. Right now React Native Maco has, it doesn't do any bubbling.
[03:46 - 04:00] It doesn't prevent that if there is any element on top of this element, then it doesn't trigger the on mouse enter option. So let's say I put another view in here.
[04:01 - 04:09] I'm going to make this absolutely position. This is just to show you guys what this does.
[04:10 - 04:15] And I'm going to say this is a background. What does this show?
[04:16 - 04:22] OK, great. So I'm going to make this cover it a little bit here.
[04:23 - 04:35] Great. So here you can see, even though that there is an element or I can actually move this because right now this is inside of my touchable opacity.
[04:36 - 04:49] So it makes sense. But if I move this outside of it and I am just going to let me think about this .
[04:50 - 04:53] I'm going to pass the right zero. OK, perfect.
[04:54 - 05:04] Right, so now you can see my touchable opacity is the one that has the on mouse enter and mouse leaf. And I have a view on top of this touchable opacity.
[05:05 - 05:14] So in theory, you would expect that the on mouse enter or leaf function wouldn 't trigger, but it does. Right, unfortunately, it is one of the things that currently not working.
[05:15 - 05:20] Maybe in the future it will get solved. But for now we just kind of have to live with it.
[05:21 - 05:35] So make sure whenever you have any overlay things will look a little bit broken . So try to make your overlays not overlap any element that might have a hover state.
[05:36 - 05:43] It's unfortunate, but it is what it is. There is one more detail that we're going to take a look into.
[05:44 - 05:54] So depending on your macro settings, let me just show it to you. Sometimes or some users might have keyboard navigation on.
[05:55 - 06:19] So that means whenever I am on my application and I click on a button or just let me hear, for example, right, I could use my keyboard to highlight different UI elements. But sometimes you might have a hover in box, which makes messes with your design.
[06:20 - 06:21] Let's just say that. Right.
[06:22 - 06:29] So you might want to disable this. So in order to do this, we're going to use another undocumented API.
[06:30 - 06:52] I'm going to go into my books container and on my touchable opacity for my books, I'm going to add the enable focus ring prop and I'm going to set it to false. Now again, because this is undocumented and there is no way to type check it.
[06:53 - 06:59] I'm just going to disable it like that. And now you see it's not visible anymore.
[07:00 - 07:15] Right. So there's a ton of little details like this that you might have to take a look to think about how your app is interacting on a desktop and what are the differences of it interacting on the mobile device.
[07:16 - 07:22] But these are just two examples that should kind of give you an idea what's important to keep an eye out for.