react-navigation
Set of react components, hooks and providers to easily kickoff a navigation environment in web projects.
Installation
$ npm install @moxy/react-navigation
This library is written in modern JavaScript and is published in both CommonJS and ES module transpiled variants. If you target older browsers please make sure to transpile accordingly.
Motivation
Most websites have a navbar and a drawer to provide an easy access to other pages. The creation process is usually remade project after project with little to no reutilization.
By analysing a few projects, most of the logic was identical in every single one. This raised a few questions and one solution to the problem would be to have a set of react tools to simplify the process.
A concern that came from the proposed solution was that every single website has different designs for a navbar or a drawer. Although this is true, their behaviour is usually the same. So, the solution should only deal with logic and behaviours while giving total freedom of the content that is rendered.
[@moxy/next-layout](https://github.com/moxystudio/next-layout)
, where Layout
components don't unmount on each page change, beware you will have to listen to router events to make sure the drawer closes even if the page change is triggered by the browser's history buttons. See Handling router events section to check how it can be done in Next.js projects.
Usage
import React from 'react';
import { NavigationProvider, Navbar, Drawer, useNavigation } from '@moxy/react-navigation';
const MyNavigationHelper = () => {
const { drawer } = useNavigation();
return (
<>
<span>{ `Is Drawer Open? ${drawer.isOpen}` }</span>
<button onClick={ drawer.open }>Open Drawer</button>
<button onClick={ drawer.close }>Close Drawer</button>
<button onClick={ drawer.toggle }>Toggle Drawer</button>
</>
);
}
const App = ({ Page, pageProps }) => (
<NavigationProvider>
<Navbar
placement="top"
behaviour="hideOnScrollDown"
className="navbar">
<p>This is the content of the navbar.</p>
<MyNavigationHelper />
</Navbar>
<Drawer
withOverlay
placement="left"
className="drawer"
overlayClassName="overlay">
<p>This is the content of the navbar.</p>
</Drawer>
<Page { ...pageProps } />
</NavigationProvider>
);
export default App;
Import the styleguide base styles in the app's entry CSS file:
@import "@moxy/react-navigation/dist/index.css";
..or in your entry JavaScript file:
import '@moxy/react-navigation/dist/index.css';
Handling router events
Taking MyNavigationHelper
component as example:
import { useRouter } from 'next/router';
const MyNavigationHelper = () => {
const router = useRouter();
const {
drawer: {
open: openDrawer,
close: closeDrawer,
toggle: toggleDrawer,
isOpen: isDrawerOpen,
}
} = useNavigation();
useEffect(() => {
const handleRouteChange = () => {
closeDrawer();
};
router.events.on('routeChangeStart', handleRouteChange);
return () => {
router.events.off('routeChangeStart', handleRouteChange);
};
}, [closeDrawer, router.events]);
return (
<>
<span>{ `Is Drawer Open? ${isDrawerOpen}` }</span>
<button onClick={ openDrawer }>Open Drawer</button>
<button onClick={ closeDrawer }>Close Drawer</button>
<button onClick={ toggleDrawer }>Toggle Drawer</button>
</>
);
}
We are listening to routeChangeStart
event for the sake of this example. You can check here a complete list of the supported events for the Next.js Router.
Styling
Each provided component accepts classNames for styling. Although there might be a need to style conditionally, some auxiliary data attributes are provided and can be styled like so:
.drawer,
.drawer[data-open="false"] {
background-color: red;
}
.drawer[data-open="true"] {
background-color: blue;
}
.overlay,
.overlay[data-open="false"] {
opacity: 0;
}
.overlay[data-open="true"] {
opacity: 0.5;
}
API
NavigationProvider
A context is created to help interact with navigation elements. The NavigationProvider
component acts as a provider to allow other consuming components to subscribe to context changes.
All consumers that are descendants of the NavigationProvider
will re-render whenever the navigation context changes.
Any consumer component that uses the useNavigation
hook or the withNavigation
HOC must be descendant from this provider.
useNavigation
Hook that returns the current state of the navigation context.
withNavigation
HOC that provides the current state of the navigation context in the form of a prop named navigation
.
Navbar
Navbar
is a component that renders a navigation bar with a few pre-available benefits. No content is rendered by default based on the uniqueness of every navbar, delegating that responsibility to the developer.
The following props are available for the Navbar
component:
children
Type: any
| Required: false
The content of the navbar.
placement
Type: string
| Options: top
, right
, bottom
, left
| Default: top
The placement of the navbar in relation to the viewport.
behaviour
Type: string
| Options: hideOnScrollDown
| Required: false
A predefined navbar behaviour.
className
Type: string
| Required: false
A className to apply to the component.
Drawer
Drawer
is a component that renders a drawer with a few pre-available benefits. No content is rendered by default based on the uniqueness of every drawer, delegating that responsibility to the developer.
The following props are available for the Drawer
component:
children
Type: any
| Required: false
The content of the drawer.
placement
Type: string
| Options: top
, right
, bottom
, left
| Default: left
The placement of the drawer in relation to the viewport.
withOverlay
Type: boolean
| Default: true
An overlay that renders together with the drawer. When clicked, closes the drawer.
lockBodyScroll
Type: boolean
| Default: true
Disables body scroll whenever the drawer is open. It keeps the drawer scroll if needed.
className
Type: string
| Required: false
A className to apply to the drawer.
overlayClassName
Type: string
| Required: false
A className to apply to the overlay.
Tests
$ npm test
$ npm test -- --watch # during development
Demo
A demo Next.js project is available in the /demo
folder so you can try out this component.
First, build the react-navigation
project with:
$ npm run build
To run the demo, do the following inside the demo's folder:
$ npm i
$ npm run dev
Note: Everytime a change is made to the package a rebuild is required to reflect those changes on the demo.
FAQ
I can't override the component's CSS, what's happening?
There is an ongoing next.js issue about the loading order of modules and global CSS in development mode. This has been fixed in v9.3.6-canary.0, so you can either update next.js
to a version higher than v9.3.5
, or simply increase the CSS specificity when overriding component's classes, as we did in the demo
, e.g. having the page or section CSS wrap the component's one.
License
Released under the MIT License.