DEV Community

Mohamed Idris
Mohamed Idris

Posted on

Fixed vs Dynamic Nav Links Menu Toggle Styling in React

In this post, we'll explore how to create a responsive navbar in React with a menu toggle. We'll compare two methods for controlling the height of the menu: fixed height and dynamic height.


1. Fixed Height Approach

In this approach, we set a fixed height when the menu is opened. This method works well when you know the menu’s height in advance.

import { useState } from 'react';
import { FaBars } from 'react-icons/fa';
import { links } from './data';

const Navbar = () => {
  const [showLinks, setShowLinks] = useState(false);

  return (
    <nav>
      <button className="nav-toggle" onClick={() => setShowLinks(!showLinks)}>
        <FaBars />
      </button>

      <div className={`links-container ${showLinks ? 'open' : ''}`}>
        <ul className="links">
          {links.map(link => (
            <li key={link.id}>
              <a href={link.url}>{link.text}</a>
            </li>
          ))}
        </ul>
      </div>
    </nav>
  );
};

export default Navbar;
Enter fullscreen mode Exit fullscreen mode

CSS for Fixed Height:

.links-container {
  height: 0;
  overflow: hidden;
  transition: height 250ms ease-in-out;
}

.links-container.open {
  height: 10rem; /* Adjust as needed */
}
Enter fullscreen mode Exit fullscreen mode

In this example, the menu container's height is set to 0 by default, and when the menu is opened, the height is set to 10rem.


2. Dynamic Height Approach

The dynamic height approach automatically adjusts the menu’s height based on its content. It’s a great choice if you have a variable number of items.

import { useState, useRef } from 'react';
import { FaBars } from 'react-icons/fa';
import { links } from './data';

const Navbar = () => {
  const [showLinks, setShowLinks] = useState(false);
  const linksRef = useRef(null);

  const linksContainerStyles = {
    height: showLinks ? `${linksRef.current?.offsetHeight}px` : 0,
  };

  return (
    <nav>
      <button className="nav-toggle" onClick={() => setShowLinks(!showLinks)}>
        <FaBars />
      </button>

      <div className="links-container" style={linksContainerStyles}>
        <ul className="links" ref={linksRef}>
          {links.map(link => (
            <li key={link.id}>
              <a href={link.url}>{link.text}</a>
            </li>
          ))}
        </ul>
      </div>
    </nav>
  );
};

export default Navbar;
Enter fullscreen mode Exit fullscreen mode

CSS for Dynamic Height:

.links-container {
  overflow: hidden;
  transition: height 250ms ease-in-out;
}
Enter fullscreen mode Exit fullscreen mode

In this case, the height is dynamically calculated based on the content inside the menu. When the menu is opened, its height adjusts to fit the content.


Key Differences:

  • Fixed Height: The height is set manually and doesn’t change unless you update it. It’s simple but less flexible.
  • Dynamic Height: The height adjusts automatically based on the content. It's more flexible but slightly more complex.

Conclusion: Both methods are great for different use cases. If your menu has a fixed number of items, use the fixed height approach. If the number of items may change or you want more flexibility, go with the dynamic height approach.

Credits: John Smilga's course

Top comments (1)

Collapse
 
edriso profile image
Mohamed Idris

Full Navbar Example

Here’s the complete responsive navbar example using the dynamic height technique with useRef and inline styles. The menu height is calculated based on its content, so it adapts automatically if links are added or removed.

import { useRef, useState } from 'react';
import { FaBars } from 'react-icons/fa';
import { links, socialLinks } from './data';
import logo from './logo.svg';

const Navbar = () => {
  const [showLinks, setShowLinks] = useState(false);
  const linksRef = useRef(null);

  const linksContainerStyles = {
    height: showLinks ? `${linksRef.current.offsetHeight}px` : 0,
  };

  return (
    <nav>
      <div className="nav-center">
        <div className="nav-header">
          <img src={logo} alt="logo" className="logo" />
          <button
            className="nav-toggle"
            onClick={() => setShowLinks(!showLinks)}
          >
            <FaBars />
          </button>
        </div>

        <div className="links-container" style={linksContainerStyles}>
          <ul className="links" ref={linksRef}>
            {links.map((link) => (
              <li key={link.id}>
                <a href={link.url}>{link.text}</a>
              </li>
            ))}
          </ul>
        </div>

        <ul className="social-icons">
          {socialLinks.map(({ id, url, icon }) => (
            <li key={id}>
              <a href={url} target="_blank" rel="noreferrer">
                {icon}
              </a>
            </li>
          ))}
        </ul>
      </div>
    </nav>
  );
};

export default Navbar;
Enter fullscreen mode Exit fullscreen mode

CSS (Dynamic Height Menu):

.links-container {
  overflow: hidden;
  transition: height 250ms ease-in-out;
}

.social-icons {
  display: none;
}

@media screen and (min-width: 800px) {
  .nav-center {
    max-width: 1170px;
    margin: 0 auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 1rem;
  }

  .nav-toggle {
    display: none;
  }

  .links-container {
    height: auto !important;
  }

  .links {
    display: flex;
    gap: 0.5rem;
  }

  .social-icons {
    display: flex;
    gap: 0.5rem;
  }
}
Enter fullscreen mode Exit fullscreen mode

This approach keeps the animation smooth while ensuring the navbar stays flexible and content-aware—perfect for responsive layouts where the number of links might change.

How it looks on mobile

How it looks on Desktop