This post was created using version 3.x.x of Refine. Although we plan to update it with the latest version of Refine as soon as possible, you can still benefit from the post in the meantime.
You should know that Refine version 4.x.x is backward compatible with version 3.x.x, so there is no need to worry. If you want to see the differences between the two versions, check out the migration guide.
Just be aware that the source code example in this post have been updated to version 4.x.x.
Introduction
In this article, you'll see how to create responsive navbars in Refine apps using the following CSS frameworks:
- Tailwind CSS
- Bootstrap
Refine is a React-based framework for building internal tools using helper hooks, components, and providers. It provides amazing functionality for rapid development while ensuring extreme customizability. Everything is separate from your UI components and business logic in refine-based Apps. So, you can create UI components or code your flow. You can build admin panels, B2B applications, and dashboards using refine. But it's not limited to only these three scenarios.
Steps we'll cover:
- Setting Up a Refine App
- Responsive Navbar with Tailwind
- Add navigation functionality to the navbar
- Responsive Navbar with Bootstrap
- Add React Router to Bootstrap Navbar
Setting Up a Refine App
We'll use superplate tool to create an empty React-based Refine application.
npm create refine-app@latest refine-navbar -- -o refine-headless -b v3
Navigate to the refine-navbar
folder and run npm run dev
command.
We're using four resources posts
, categories
, users
and events
for the navigation purpose.
Create pages/posts
folder
export const postList = () => <p className="post">Post Page</p>;
Create pages/categories
folder
export const categoryList = () => <p className="category">Category Page</p>;
Create pages/users
folder
export const userList = () => <p className="user">User Page</p>;
Create pages/events
folder
export const eventList = () => <p className="event">Event Page</p>;
Create index.tsx
file inside pages
folder and add the following code to it.
export * from "./posts";
export * from "./categories";
export * from "./users";
export * from "./events";
<Refine />
is the root component of the application. resources
is a property of <Refine />
representing API Endpoints. The name
property of every single resource should match one of the endpoints in your API.
resources
use Page components to handle data and perform rendering. Page components are passed to resources as an array of objects.
Add these resources
as a prop to the <Refine />
component:
import { Refine } from "@refinedev/core";
import React from "react";
import "App.css";
import routerProvider from "@refinedev/react-router-v6";
import dataProvider from "@refinedev/simple-rest";
import { postList, categoryList, userList, eventList } from "pages";
const App: React.FC = () => {
return (
<Refine
routerProvider={routerProvider}
dataProvider={dataProvider("https://api.fake-rest.refine.dev")}
resources={[
{ name: "posts", list: postList },
{ name: "categories", list: categoryList },
{ name: "users", list: userList },
{ name: "events", list: eventList },
]}
/>
);
};
export default App;
Refine works based on consuming data from APIs. You can consume Rest APIs using dataproviders
. Data providers are Refine components that make it possible to consume APIs and data services easily.
For this tutorial, we don't want consume API since we only want to focus navigating. The key point is dataProvider
is required property. So we need give it anyway even if we don't want to consume the API. We use the fake Rest API available at https://api.fake-rest.refine.dev/
.
Also, add following code inside App.css
:
.post,
.category,
.user,
.event {
text-align: center;
}
and import it inside App.tsx
:
import "App.css";
Responsive Navbar with Tailwind
Tailwind provides utility classes for creating components. We need to set up Tailwind CSS before starting to create a navbar with it.
Install tailwindcss and its peer dependencies using the following command:
npm i -D tailwindcss postcss autoprefixer
Then, init command to generate tailwind.config.js
file.
npx tailwindcss init
Now, add paths of all template files in tailwind.config.js
file:
module.exports = {
content: ["./src/**/*.{js,jsx,ts,tsx}"],
};
After that, add all @tailwind directives in src/index.css
file:
@tailwind base;
@tailwind components;
@tailwind utilities;
Add "index.css" import inside the src/App.tsx
file.
import "index.css";
Now, We can use Tailwind to style our application.
We're using the following tailwind classes for creating a responsive navbar layout:
flex
sets the display mode of container to flex.flex-col
changes the flex direction to column.min-h-screen
sets the minimum height of the element to min-height: 100vh.container max-auto
centers the container.flex justify-between
adds space between the flex items.w-32
indicates that element has (32*4) 128px width.ml-2
provides 8px margin to the element from left.items-center
pushes items to the center.hidden
sets element visibility to hidden.md:flex
displays flex when screen size is atleast medium.md:hidden
sets visibility to hidden when screen size is atleast medium.text-green-500
changes text color to green with 500 font weight.bg-white
sets the background color of the element to white.
Layout component is used for the customization of Refine app's layout. Create components/Layout.tsx
file inside the src
folder.
Create the following navbar using Tailwind CSS inside the Layout
component. We can get all the menuItems
from <Refine />
using useMenu()
hook.
import { useMenu, LayoutProps } from "@refinedev/core";
import React from "react";
export const Layout: React.FC<LayoutProps> = ({ children }) => {
const { menuItems } = useMenu();
return (
<div className="flex min-h-screen flex-col">
<div className="mb-2 md:border-b py-2">
<div className="container mx-auto">
<div className="flex justify-between gap-2">
<img
className="w-32 ml-2"
src="https://refine.dev/img/refine_logo.png"
alt="Logo"
/>
<ul className="hidden md:flex">
{menuItems.map(({ name, route }) => (
<li key={name} className="float-left">
<a className="flex cursor-pointer items-center gap-1 rounded-sm px-2 py-1 mt-2 capitalize decoration-indigo-500 decoration-2 underline-offset-1 transition duration-300 ease-in-out">
<span className="text-green-500">{name}</span>
</a>
</li>
))}
</ul>
</div>
</div>
</div>
<div className="bg-white">{children}</div>
</div>
);
};
This layout is passed as a prop to the <Refine />
component:
import { Layout } from "components/Layout";
const App: React.FC = () => {
return (
<Refine
...
Layout={Layout}
/>
);
};
The output of the above code is as follows:
Let's make it mobile responsive by adding the mobile menu:
...
<div className="flex flex-col md:hidden border-b pl-3">
{menuItems.map(({ name, route }) => (
<a className="flex cursor-pointer items-center gap-1 rounded-sm px-2 py-1 mt-2 capitalize decoration-indigo-500 decoration-2 underline-offset-1 transition duration-300 ease-in-out"
>
<span className="text-green-500">{name}</span>
</a>
))}
</div>
...
Add navigation functionality to the navbar
We need to use Link
component in the Layout.tsx
will look like this:
import { useMenu, LayoutProps, useRouterContext } from "@refinedev/core";
import React from "react";
export const Layout: React.FC<LayoutProps> = ({ children }) => {
const { menuItems } = useMenu();
const { Link } = useRouterContext();
return (
<div className="flex min-h-screen flex-col">
<div className="mb-2 md:border-b py-2">
<div className="container mx-auto">
<div className="flex justify-between gap-2">
<img
className="w-32 ml-2"
src="https://refine.dev/img/refine_logo.png"
alt="Logo"
/>
<ul className="hidden md:flex">
{menuItems.map(({ name, route }) => (
<li key={name} className="float-left">
<Link
className="flex cursor-pointer items-center gap-1 rounded-sm px-2 py-1 mt-2 capitalize
decoration-indigo-500 decoration-2 underline-offset-1 transition duration-300 ease-in-out"
to={name}
>
<span className="text-green-500">{name}</span>
</Link>
//highlight-
</li>
))}
</ul>
</div>
</div>
</div>
<div className="bg-white">{children}</div>
</div>
);
};
Responsive Navbar with Bootstrap
I've already walked you through setting up Refine app. Now, we'll create navbar inside Layout.tsx
and pass it as a prop to <Refine />
component.
First, install react-bootstrap:
npm install bootstrap react-bootstrap
react-bootstrap
comes only with js. It doesn't have any CSS styles. That's why we installed bootstrap, which contains CSS.
import "bootstrap/dist/css/bootstrap.min.css";
Add navbar component inside the layout component and then create navbar items. We'll use Refine logo for our navbar.
import { Navbar, Nav } from "react-bootstrap";
<div>
<Navbar className="navbar-border">
<img
className="brand-image"
src="https://refine.ams3.cdn.digitaloceanspaces.comundefined"
width="100px"
height="100px"
/>
<Nav>
{menuItems.map(({ name, label, icon, route }) => (
<Nav.Link className="nav-link">{name}</Nav.Link>
))}
</Nav>
</Navbar>
<div>{children}</div>
</div>;
Add following CSS classes to App.css
file:
.navbar-border {
border-bottom: 1px solid gray;
}
.nav-link {
margin-top: 5px;
text-transform: capitalize;
}
.brand-image {
margin: 0 15px !important;
}
<Navbar.Toggle />
creates hamburger menu when screen size equals to minimum width set by expand
attribute in Navbar
component. You can do this in the following way:
import { useMenu, LayoutProps } from "@refinedev/core";
import React from "react";
import "bootstrap/dist/css/bootstrap.min.css";
import { Navbar, Nav } from "react-bootstrap";
export const Layout: React.FC<LayoutProps> = ({ children }) => {
const { menuItems } = useMenu();
return (
<div>
<Navbar className="navbar-border" expand="lg">
<img
className="brand-image"
src="https://refine.ams3.cdn.digitaloceanspaces.comundefined"
width="100px"
height="100px"
/>
<Navbar.Toggle />
<Navbar.Collapse>
<Nav>
{menuItems.map(({ name, label, icon, route }) => (
<Nav.Link className="nav-link">{name}</Nav.Link>
))}
</Nav>
</Navbar.Collapse>
</Navbar>
<div>{children}</div>
</div>
);
};
Add React Router to Bootstrap Navbar
Now, we're done with creating a responsive navbar using react-bootstrap
.
Add <Link>
component inside <Nav>
like this:
import { useMenu, LayoutProps, useRouterContext } from "@refinedev/core";
import React from "react";
import "bootstrap/dist/css/bootstrap.min.css";
import { Navbar, Nav } from "react-bootstrap";
export const Layout: React.FC<LayoutProps> = ({ children }) => {
const { menuItems } = useMenu();
const { Link } = useRouterContext();
return (
<div>
<Navbar className="navbar-border" expand="lg">
<img
className="brand-image"
src="https://refine.ams3.cdn.digitaloceanspaces.comundefined"
width="100px"
height="100px"
/>
<Navbar.Toggle />
<Navbar.Collapse>
<Nav>
{menuItems.map(({ name, label, icon, route }) => (
<Link className="nav-link" to={name}>
<span>{name}</span>
</Link>
))}
</Nav>
</Navbar.Collapse>
</Navbar>
<div>{children}</div>
</div>
);
};
Conclusion
Refine works with any custom design or UI framework. Every UI framework helps in creating layouts by providing utility classes or pre-designed components. In this article we implemented responsive navbar using Tailwind and Bootstrap. You can choose any framework and design components according to your needs.
Example
npm create refine-app@latest -- --example blog-responsive-navbar