Sliding menus are all the rage in UIs today. All the cool kids are building them, and your friends probably just can’t get enough of them. These menus are basically off-screen elements that slide into view when you click or tap on something. That something could be an arrow, a hamburger icon, or something else that indicates a menu will appear.
To see a sliding menu in action, go here: https://www.kirupa.com/react/examples/slidingmenu_css/index.html.
You’ll see a yellow menu with some navigation links smoothly slide in. If you click a navigation link or anywhere in the yellow region inside that menu, the menu slides back (really smoothly again, of course) and the content behind it reappears. Let’s look at how to create all of this using React.
Note: For a Non-React Solution
If you’re looking to create this menu using plain JavaScript without any React wizardry, the tutorial Creating a Smooth Sliding Menu (http://bit.ly/plainSidingMenu) has you covered.
Before we jump into the code, let’s take a few moments to better understand how exactly our sliding menu works. Starting at the very top, we have our page that displays some content:
When you decide to bring up the menu (by clicking/tapping the blue circle in our example), the menu magically slides into view:
The way this sliding menu works isn’t as crazy as it seems. The menu is never truly nonexistent; it is simply hidden outside the view. To see what that looks like, check out the following diagram:
Just to the left of the content what we see is our menu, patiently hiding until it is called upon. We do that by shifting the menu as far left as we can until it’s fully out of view. Figuring out how far to shift is easy. Our menu’s size is the same as our browser’s window (a.k.a. the viewport) size because we want the menu to fully cover up whatever is shown. Given that detail, we just shift the menu left by the browser’s width. One way of doing that might be by using some CSS that looks as follows:
We set our menu’s position to fixed
. This single change gives our menu a whole lot of magical capabilities. For starters, it ensures that normal layout rules no longer apply to it. We can position our menu anywhere we want using normal x and y values, and the menu won’t shift away from where we have it positioned. If that isn’t awesome enough, our menu won’t even display a scrollbar if we happen to hide it somewhere offscreen.
All this is a good thing because we hide our menu offscreen by setting our menu’s left and top properties to 0
and setting our menu’s transform property to a translate3d
method with a horizontal value of -100vw
. The negative value ensures that we shift the menu left by the amount equivalent to our browser window’s width. While not directly related to position, the size of our menu plays an important role as well. That’s why, in this CSS snippet, we have the width
and height
properties set with values of 100vw
and 100vh
, respectively, to ensure that our menu’s size is the same as our browser window’s size.
What Are These vw and vh Units?
If you’ve never seen the vw and vh units, they stand for viewport width (vw) and viewport height (vh). They’re a bit similar to percentage values. Each unit is 1/100th the width or height of your viewport (what we’ve been simply calling the browser window). For example, a value of 100vw means that its value is the full width of our browser window. Similarly, 100vh refers to a value that is the full height of our browser window.
When the menu is called upon to slide into view, we slide the menu right until its horizontal position is the same as our browser window origin. If we had to look at what the CSS for it might look like, this would be an easy change from what we already have. We simply set our transform
property’s translate3d
method and set the horizontal position to a value of 0vw
.
That might look something like this:
This change ensures that our menu is shifted right from being hidden offscreen (with a horizontal translate value of -100vw
) and is now visible. When our menu needs to disappear, we can translate it back:
The biggest thing we haven’t spoken about is the animation that makes the sliding look cool. This is done using a simple CSS transition that animates the transform
property:
If you’re not familiar with CSS transitions, it’s a very simple concept to wrap your brain around. I don’t explain it here, so take a few moments and read through the short Introduction to CSS Transitions article (https://www.kirupa.com/html5/introduction_css_transitions.htm) for an overview.
So far, we’ve taken a bird’s-eye view of how our sliding menu works. A few details need to be looked at, but we’ll do that in the next couple sections when we actually build this menu.
Now that you have a basic idea about how a sliding menu works, let’s turn all that theoretical knowledge into some sweet JSX and code. The first thing we’re going to do is look at our example in terms of the individual components that will make it up.
At the very top, we have our MenuContainer
component:
This component is responsible for doing nonvisual things like managing state, hosting our Menu
and MenuButton
components, and displaying some of the initial text. The bird’s-eye view looks a bit like this:
In the next few sections, we’ll start creating these components and getting the example up and running.
Use create-react-app
to create a new project called slidingmenu
. If you aren’t familiar with how to do that, check out Chapter 13, “Setting Up Your React Dev Environment Easily,” to walk through the details of creating and working with React projects. After you’ve created your project, you want to start from a blank slate. Delete everything in your public
and src
folders. You’ll re-create the necessary pieces shortly.
Let’s start by creating our HTML document. In your public
folder, create a file called index.html
. Inside it, add the following contents:
This HTML page is simply the destination where all of our React components will eventually render their output.
Next, you want to create a file called index.js
in the src
folder that will be responsible for teeing things up in the code. Add the following content into this file:
The render
call here is responsible for displaying the output of our MenuContainer
component into the container
div
element we specified in HTML a few moments ago. In our import
statements, besides pulling in the react
and react-dom
libraries, we are referencing index.css
and our MenuContainer
component. That’s all there is to our index.js
file.
Next we’re going to create the index.css
file in our src
folder and get the page’s basic styling defined. In this file, add the following two style rules:
There isn’t much to say about these style rules, so the last thing we do to get our initial app set up is create our MenuContainer
component. Create a file called MenuContainer.js
in the src
folder and add the following JS and JSX into it:
Be sure to save the changes you made to all of your files, and test your app (using npm start
) to ensure that your initial setup of the app works fine. If everything worked out properly, your default browser will launch and you’ll see something that looks as follows:
There’s no menu to slide or button to press; we’ll add both of those in the next couple sections.
With the initial setup out of the way, it’s time for the fun part: actually building the menu. Our menu is shown or hidden as follows:
1. When you click a button, the menu slides into view.
2. When you click anywhere on the menu, the menu slides out of view.
This means that we need to account for a few things going on. We need to maintain some state to keep track of whether the menu is hidden or shown. This state needs to be something we update from both the button and the menu because clicking on either will toggle whether the menu is visible. We need our state to live in a common location that both the menu and the button can access. That common location will be inside our MenuContainer
component, so let’s add the code relating to our state logic.
In the MenuContainer.js
file, add the constructor and toggleMenu
methods just above our render
method:
The code you’ve just added should look like a walk in the park by now. You’re storing a variable called visible
in your state object, and you’re creating a method called toggleMenu
that will be responsible for toggling whether visible
is true
or false
.
Next up is dealing with the click
events on the button and menu. If the goal is to update our state from inside our MenuContainer
component, we need to place our event handler inside MenuContainer
as well. Go ahead and add the following highlighted lines:
When the handleMouseDown
method is called, we call toggleMenu
, which toggles whether the menu appears. At this point, you’re probably wondering where the actual code for dealing with a click
event is. What exactly will trigger a call to handleMouseDown
? The answer is, nothing so far! We’ve done things in a bit of a reverse order and defined our event handler first. We handle the association between our event handler and our click
event in a few moments when dealing with our button and menu components.
In your src
folder, create two files called MenuButton.js
and MenuButton.css
. Then open MenuButton.js
in your code editor. Inside it, add the following lines of code:
Take a moment to see what this code is doing. There isn’t a whole lot going on. We define a button element called roundButton
, and we associate the onMouseDown
event with a prop we are referencing as handleMouseDown
. Before moving on, open MenuButton.css
and add the following style rules:
Now it’s is time to actually instantiate our newly created MenuButton
component. Go back to the MenuContainer
component and add the following highlighted line inside the render
method:
For this line to actually do something, be sure to add the appropriate import
statement at the top for our MenuButton.js
file. That’s an easy one to overlook!
Notice that we are passing in a prop called handleMouseDown
, and its value is the handleMouseDown
event handler that we defined earlier. This ensures that when you click the button inside the MenuButton
component, the handleMouseDown
method that lives in the MenuContainer
component gets called. All of this is great, but our button isn’t very useful without a menu to help slide into view. We’ll fix that next.
It’s time to create our Menu
component that will be responsible for all things dealing with the menu. Before we actually create this component, let’s pretend that it already exists and call it from our render
method inside our MenuContainer
. Add the following highlighted call to our (currently imaginary) Menu
component just below where you added the call to MenuButton
a few short moments earlier:
Add the import statement for Menu.js
as well. Getting back to the Menu
component, look at the props you’re passing in. The first prop should look familiar to you. It is handleMouseDown
and its value is our handleMouseDown
event-handling method. The second prop is called menuVisibility
. Its value is the current value of our visible
state property. Now let’s go ahead and actually create our Menu
component and see, among other things, how these props get used.
In the same src
folder we have been partying in for the past few sections, add one file called Menu.js
and another file called Menu.css
. Inside Menu.js
, add the following contents:
Pay attention to the JSX in the return
statement. We have a div
element called flyoutMenu
with some sample content. In our div
element, we call our handleMouseDown
event-handling method (passed in via a prop) when the onMouseDown
event is overheard. Next, we set a class
value on this element; the value is the result of evaluating a variable called visibility
. As you might recall, class
is a reserved name in JavaScript and you can’t use it directly in our JSX; it has to be specified as className
.
Getting back to our code, the value of visibility
is set a few lines earlier:
The value is either hide
or show
, depending on whether the menuVisibility
prop (whose value is specified by our visible
state property) is true
or false
. While it might not look like it, the code revolving around className
plays a really important role in determining whether your menu is actually visible. When we look at our CSS, you’ll see why. Now open Menu.css
and add the following style rules into it:
The CSS you see here mostly deals with how our menu itself looks, but the actual showing and hiding of the menu is handled by the #flyoutMenu.hide
and #flyoutMenu.show
style rules. Which of these style rules becomes active depends entirely on the code we looked at earlier. In our flyoutMenu
div
element, remember that the class
value on the generated HTML (which our CSS maps to) will be either hide
or show
, depending on what value we set for className
. Pretty cool, right?
At this point, we’re fully done with all our coding. Be sure to save all your changes and ensure that the app works just like the example we started with. Don’t nuke this project, though. We’ll be revisiting this and addressing some major shortcomings in a little bit.
This is one of the first examples we’ve looked at in which we’re using React to create a common UI occurrence, a sliding menu. As part of this, you learned more about the interplay between components, such as dealing with events/event handlers, sharing state, and so on. As we look at more examples together, you’ll see that there isn’t a whole lot more to React than what you’ve seen here. All that remains is a clever arrangement and rearrangement of the same concepts in more complex scenarios. This doesn’t mean we’re done, though. There’s more React to be had and more examples to create and fully understand!
Note: If you run into any issues, ask!
If you have any questions or your code isn’t running like you expect, don’t hesitate to ask! Post on the forums at https://forum.kirupa.com and get help from some of the friendliest and most knowledgeable people the Internet has ever brought together!
18.227.24.209