DEV Community

Cover image for Part 1.1 - Build a fullstack blogging website using MERN ( MongoDB, ReactJS, ExpressJS and NodeJS )
Modern Web
Modern Web

Posted on

Part 1.1 - Build a fullstack blogging website using MERN ( MongoDB, ReactJS, ExpressJS and NodeJS )

👋 Hey there, today in this blog we will start a new series where we will learn “how to make a fullstack blogging website using MERN stack” basically we will make a website very similar to medium.com.

You probably think it is just some other tutorial claiming to make a fullstack website with just simple things but I will say, you should see the website demo first available below. You will see a lot of features there from having a fully working modern editor for writing blogs, to features like, like a blog, comment on blog and even replies to any comment ( basically nested comments ) on top of that a very good dashboard UI to manage blog and view insights like “like count, read count, comments count” and did I mention any interaction you do on website will store in database as a notification for other user. In short, its a kind of project which will just shine in your portfolio.

Okay so let’s see how we can start building this project, I can’t wait to start this blog.

This project is so big so the tutorial of this project will be in parts. In video formats it will be 4 or 5 parts that you can find on “Modern Web” youtube channel and In blogs there will be 3 - 4 parts for every video part

Website Demo

If you want to see the full website in action, all features from simple to advance. You can watch the demo below. The video below also include this blog in video format.

You can download full source code of this project if you want. Download Source Code

Github Initialisation

Okay, in order to follow this project, you need to download this github repo.

You can fork the repo in your account and then clone it on your system or you can just download the repo without forking it to your account. Once you have the repo, you will get 2 folders inside it

blogging website - frontend - this folder is frontend ( react ) code

server - this folder is backend ( node ) code

open both of these files on terminal separately because we need to install the packages in order to make this project. You don’t have to worry about any package name or version all of these things are mentioned in package.json file already.

blogging website - frontend folder setup

Once this folder is open in terminal, first run npm install cmd to install all the packages, after that you just need to start the frontend vite server whenever you want to access the website. You can do that by running npm run dev cmd in terminal.

server folder setup

Once this folder is open in terminal, first run npm install cmd to install all the packages.

That’s sit once you have installed all the packages we can start working on the project.

Navbar

Let’s start our project by working on our Navbar first. Let’s create navigation for easy user interaction. We will create navbar as a react component because we want to render navbar on multiple pages/routes. So open navbar.component.jsx under components folder. Create a very basic Navbar Functional component.



const Navbar = () => {
    return (
        <h1> Navbar </h1>
    )
}

export default Navbar; // default let's you import function without { } 


Enter fullscreen mode Exit fullscreen mode

Above component is returning an h1 to render for now so that we can check whether or not our component working properly. Also make sure to export the component as a default component.

Now to render it, we will go inside app.jsx file which is our app file where we will setup routes for this project later. In file you will see its returning an h1 by default. so remove that and instead add <Navbar /> to render it. ( Do not forget to import the component at top, in VScode you can do that automatically if you just press enter while typing component name from the suggestion VScode gives you )



import Navbar from "./components/navbar.component";

const App = () => {

    return (
       <Navbar />
    );

}

export default App; 


Enter fullscreen mode Exit fullscreen mode

So if you are getting “navbar” text on the page that means everything is working and if not then it’s time for you to recheck the code and see where you made mistake.

Okay, let’s create our navbar now. So instead of returning h1 return nav and we will create navbar inside it. Add Classname to it navbar because in index.css file, there is navbar class with bunch of tailwind CSS for navbar.



const Navbar = () => {
    return (
        <nav className="navbar">
            { 
                // nav elements will go here 
            }
        </nav>
    )
}


Enter fullscreen mode Exit fullscreen mode

Navbar - Logo

In our navbar, we have a logo and whenever user click on that logo we want to redirect user to homepage. So first let’s make the logo inside navbar.



<nav className="navbar">

    <img src={logo} className="flex-none w-10" />

</nav>


Enter fullscreen mode Exit fullscreen mode

img element has flex-none class, so that our navbar flex won’t affect its size. In the src I have given {logo} , if you don’t know what this { } used for then its simple inside JSX to access/write JS you can use { } and inside the brackets you can use JS and you can even call variable inside it to access variable name. So src is basically whatever this logo variable is. Now what is it ?

Well in order to use any external file in react you have to import it, whether its a component, function, image, svg anything. You have to first import it and this logo is exactly the import of image at the top of navbar.component.jsx file.



import logo from "../../imgs/logo.png"; // img path respective to components folder as the file is inside components folder

// rest of the code


Enter fullscreen mode Exit fullscreen mode

Output

Image description

Okay we got img but how we can redirect user to / ( home route ). Well one way is to wrap the img inside an a tag.



<a href="/">
    <img src={logo} className="flex-none w-10" />
</a>


Enter fullscreen mode Exit fullscreen mode

This will redirect you whenever you will click on image. But if you notice the site. You will see whenever you are clicking on image the page get’s reload and this destroy the concept of React Single Page Application concept as whenever you will click on image. Browser will ask for the website again from the server. So then, what can we use. To resolve this issue, instead of a we will use <Link> </Link> component offered by react-router-dom . React router is a library that help you mimc the functionality of Browser routing insider React application. So using Link component of that, we can redirect the user to whatever route we want without reloading the page.

So first import it at top.



import { Link } from "react-router-dom";
import logo from "../../imgs/logo.png";

// rest of the code


Enter fullscreen mode Exit fullscreen mode

And now, wrap the img inside Link



<Link to="/" className="flex-none w-10">
    <img src={logo} className="w-full" />
</Link>


Enter fullscreen mode Exit fullscreen mode

to prop means on which route we want to redirect. I have changed the classNameas well. That just adding the flex-none functionality to Link and w-full for img to cover full width that is w-10

But now you won’t see anything in the output. Why ? Because in order to use Link or any other features/components of react-router-dom you have to first wrap the <App /> component inside <BrowserRouter> which is also a component from react-router-dom which mimics the Browser routing functionality, and since we will have the <App /> inside it. The App which is our whole project, will be able to access the BrowserRouter functionalities.

So inside main.jsx wrap the App



<BrowserRouter>
  <App />
</BrowserRouter>


Enter fullscreen mode Exit fullscreen mode

And make sure to import the BrowserRouter at the top too.



import { BrowserRouter } from 'react-router-dom'

ReactDOM.createRoot(document.getElementById('root')).render(
    // React Component
)


Enter fullscreen mode Exit fullscreen mode

Navbar - Search Box

After logo we need a search box in our navbar. Well we will make this search box functional later. But right now, let’s get the UI done. So after Link create a div and let’s create a search box input like this 👇



// inside <nav> tag after <Link> .. </Link>

<div className="absolute bg-white w-full left-0 top-full mt-0.5 border-b border-grey py-4 px-[5vw] md:border-0 md:block md:relative md:inset-0 md:p-0 md:w-auto">
    <input 
        type="text"
        placeholder="Search"
        className="w-full md:w-auto bg-grey p-4 pl-6 pr-[12%] md:pr-6 rounded-full placeholder:text-dark-grey md:pl-12"
    />
</div>


Enter fullscreen mode Exit fullscreen mode

To understand the tailwind classes I use, I suggest you watch the video tutorial as you will get better understanding of each classes. Anyway, so basically the div is a container for input and the search icon that we will create next.



// after search box input

<i className="fi fi-rr-search absolute right-[10%] md:pointer-events-none md:left-5 top-1/2 -translate-y-1/2 text-xl text-dark-grey"></i>


Enter fullscreen mode Exit fullscreen mode

For icons, I am using Flat Icons , in the Github files font awesome installation is already done, so you can use any font awesome icon directly in the project. The one I am using is fi fi-rr-search ( a magnifying glass icon )

After this we will see something like this.

Output - smaller screens

Image description

Output - medium screens

Image description

So it’s done, but in smaller screens, what we want is to show/hide the search box whenever user clicks on search icon visible on navbar. Something like 👇

Image description

To create that after the parent div of search box. Make another div and this will be a container for actions buttons on the right side in our navbar.



// after search box's div & inside nav

<div className="flex items-center gap-3 md:gap-6 ml-auto">
    <button className="md:hidden bg-grey w-12 h-12 rounded-full flex items-center justify-center">
        <i className="fi fi-rr-search text-xl"></i>
    </button>
</div>


Enter fullscreen mode Exit fullscreen mode

So this JSX element with tailwind styles will give an output like this. Where you will see the search icon button in smaller screens and as soon as you hit medium screen size, you will not get the search icon because the search box will be inside navbar in that screen size.

Output - smaller screens

Image description

Output - medium screens

Image description

Now, how we can show/hide the search box. Well to achieve this I will use React States to track whether the search box should be visible or not. So let’s create a state first to track that.



const Navbar = () => {

    const [ searchBoxVisibility, setSearchBoxVisibility ] = useState(false) // default value will be false

    return (
            // navbar code here
    )

}


Enter fullscreen mode Exit fullscreen mode

Now since we have a state now, we will toggle its value from true → false → true whenever the search icon got click. To do that add onClick to the button and run a function to call setSearchBoxVisibility function to change the state’s value.



// search icon button

<button className="md:hidden bg-grey w-12 h-12 rounded-full flex items-center justify-center"
    onClick={() => setSearchBoxVisibility(currentVal => !currentVal)}
>
    <i className="fi fi-rr-search text-xl"></i>
</button>


Enter fullscreen mode Exit fullscreen mode

currentVal is the first parameter that you can use while calling setState functions to access the most recent value of the state and to just toggle that current Boolean value, you can return the currentVal with ! in the beginning.

Now if you click on the button, it should change the state value from false → true → false and so on. But you won’t see anything because the state is changing but its value doesn’t affecting the UI. So to show or hide the search box. We will add conditional classes to it.



<div className={"absolute bg-white w-full left-0 top-full mt-0.5 border-b border-grey py-4 px-[5vw] md:border-0 md:block md:relative md:inset-0 md:p-0 md:w-auto " + 
( searchBoxVisibility ? "show" : "hide" )}
>
    { 
                // search box input and icon
        }
</div>


Enter fullscreen mode Exit fullscreen mode

Above code is just adding show or hide class on the basis of searchBoxVisibility state. show/hide classes are inside index.css file. If you didn’t get what is happening in above code. Well first, instead of " " for className there is { } is the start and the end, which means inside it we can use JS. Then, we are simply concatenating class string using “tailwind classes” + “class from the condition” . To add condition I have used ternary operator which is a short form of if else that you can use inside JSX instead of actual if else and its syntax is like this condition ? true case : false case . Now here are 2 things to remember while using classNames like this. First wrap you condition inside ( ) otherwise it will not concatenate with the string and second add a [space] at the end of the static classNames, like I have added space after md:w-auto at the end. This will make sure that the classes will have space after concatenation other wise after concatenation, if you don’t have space at the end, it will look like this md:w-autoshow instead of md:w-auto show and this will then not apply both styles to the element.

So now you should be able to show/hide the search box by clicking on the search button.

Output

Image description

But there is an issue, if you just hide the search box, and then go to medium or large screen sizes. You will notice that there is no search box and neither the search button to show/hide the search box visibility. That is because we have hidden class to the button on medium screen so its not showing and since the state is false, the parent div has hide class because of the condition. To fix this, add md:show class to the search box’s div . So that on medium screens even if we have hide class, it will have show class which will overwrite the hide styles.



<div className={"tailwind classes md:w-auto md:show " + 
( searchBoxVisibility ? "show" : "hide" )}
>
    { 
                // search box input and icon
        }
</div>


Enter fullscreen mode Exit fullscreen mode

Navbar - Sign in / sign up button

Now we want some sing in / sing up buttons + a “write” button in the navbar for easy navigation for the user. So let’s create that. Inside the div where we have search button to show/hide the search box. Add a “write” Link element which will be hidden in smaller screens.



// search icon button 

<Link to="/editor" className="hidden md:flex gap-2 link">
    <i className="fi fi-rr-file-edit"></i>
    <p>Write</p>
</Link>


Enter fullscreen mode Exit fullscreen mode

Output

Image description

Now to create sign in / sign up buttons which will redirect the user to /signin or /signup route. Code this after the above code.



// search icon button & write button

<Link className="btn-dark py-2" to="/signin">
    Sign In
</Link>
<Link className="btn-light py-2 hidden md:block" to="/signup">
    Sign Up
</Link>


Enter fullscreen mode Exit fullscreen mode

/signup button/Link will be hidden in smaller screens as we don’t want to clutter our navbar on small devices.

Output

Image description

Route Setup

So after navbar, let’s setup some routes in react app, so that we can deliver sign in / sing up form and start working on those pages. Now since, ReactJS is a SPA means a simple page application, creating routes is difficult. So we will take help of “react-router” again in order to setup Routes. So open App.jsx and let’s setup Routes.

So in return first remove everything and add Routes Component which is provided by “react-router-dom”.



import { Routes } from "react-router-dom";

const App = () => {

        return (
                <Routes>
                        { 
                            // All the routes will come here 
                        }
                </Routes>
        )

}


Enter fullscreen mode Exit fullscreen mode

Routes Component basically allows you to setup routes for you projects. Now inside it we will use Route ( without s ) Component to create each and every routes. So inside it add this.



<Routes>
    <Route path="/" element={<Navbar />}></Route>
    <Route path="/signin" element={<h1> Sing In Form </h1>}></Route>
    <Route path="/signup" element={<h1> Sing Up Form </h1>}></Route>
</Routes>


Enter fullscreen mode Exit fullscreen mode

Route component lets you define the routes using 2 props.

  • path - it defines the route path. In the above code we have created 3 Routes with /, /signup, /signin path. Where the react router deliver different Components.
  • element - it renders whatever elements you pass inside it when the path is matched. For instance, If I now access /signin path. I will see a h1 with “Sign in form” text.

After setting these 3 routes, if you go on these 3 routes, you will see the elements being render but there is a issue. Well basically, I want to show <Navbar /> component to /signin and /signup routes as well, not only those but as we will work on other pages, in most pages we want the navbar. So how we can do that, well the simple fix is that inside each page, render <Navbar /> separately, means add <Navbar /> in all pages at the top before writing their HTML. But thats not a good practice. So instead of doing that we will go for second option, which is Outlet.

Outlet is a component again provided by react-router which allows you to create nested routes and render multiple components at once. Let see how it works. So first of all we have to change our routes a little bit.



<Routes>
    <Route path="/" element={<Navbar />}> // `Navbar` will get render whenever the path matches i.e -> "/"
        <Route path="signin" element={<h1> Sing In Form </h1>} /> // h1 will get render on path -> "/signin"
        <Route path="signup" element={<h1> Sing In Form </h1>} /> // h1 will get render on path -> "/signup"
    </Route>
</Routes>


Enter fullscreen mode Exit fullscreen mode

In the above code, I have nested the signin and singup route inside / path. Which will enable you to render 2 component because when you go to /signin let’s say, then 2 condition will be true, the first is / where react router will render Navbar and then the signin route where react router will render h1. But if you see your output, on all those 3 paths you will Navbar, but no h1.

So first, congrats as we got the navbar on all these 3 paths but we lost the h1 component. Well there is nothing to worry about it. To render components in this type of nested routes. We use Outlet Component from “react-router”. We will add this Outlet on the parent route component. So in this case the parent route is / and its component is Navbar. So open navbar.component.jsx and at the end in return add <Outlet /> make sure to import that and also wrap your <nav> and <Outlet /> in an empty component ( <></> ) so that react wont’s throw any error because in react you can only render 1 parent component.

This is how your navbar.component.jsx's return will look.



return (
    <>
        <nav className="navbar">
            // navbar code
        </nav>

        <Outlet />
    </>
)


Enter fullscreen mode Exit fullscreen mode

So as long as we have Outlet in Navbar Component, we will see both routes on nested routes.

So thats sit for this blog, I hope you learned a lot by following this article. Make sure you follow me to not miss the next part whenever I will post it. Also if you want, you can checkout my channel, and show you love by subscribing me and you can watch the full tutorial of this part 1. If you have any doubt feel free to ask me in comments. Till then thanks for reading.

Top comments (0)