Search code examples
javascriptreactjsreact-routerreact-router-domchakra-ui

How to style active NavLink


How can I make the active NavLink look similar to this? I tried following the React-Router-Dom docs but it didn't give this desired look. Is it possible to pass the isActive prop from the NavLink component to the Flex component? I created a minimum representation of the sidebar down below. I'd appreciate any help.

enter image description here

Here's a minimal recreation of the sidebar made using Chakra UI: https://codesandbox.io/s/sidebar-ckm26m?file=/src/index.js

//imports

const App = () => {
  return (
    <Stack spacing={4}>
      <NavLink to="/overview">
        <Flex align="center" p="2" mx="2" ...>
          <Box p="4px" border="1px" ...>
            <AiOutlineDashboard size={16} />
          </Box>
          <Box ml={2} fontSize="sm">
            Overview
          </Box>
        </Flex>
      </NavLink>

      <NavLink to="/app">
        <Flex align="center" p="2" mx="2" ...>
          <Box p="4px" border="1px" ...>
            <IoApps size={16} />
          </Box>
          <Box ml={2} fontSize="sm">
            Apps
          </Box>
        </Flex>
      </NavLink>
    </Stack>
  )
}

export default App

Solution

  • Is it possible to pass the isActive prop from the NavLink component to the Flex component?

    Yes, it is entirely possible. The NavLink component understands and knows how to match the active route, there's no need to reinvent the wheel by using the useLocation hook and manually checking the current pathname.

    The NavLink component's children prop can take a render function that is passed the isActive prop.

    Example Implementation:

    const App = () => {
      return (
        <Box
          bg="white"
          borderRight="1px"
          w="200px"
          pos="fixed"
          overflow="auto"
          h="full"
        >
          <Stack spacing={4}>
            <NavLink to="/overview">
              {({ isActive }) => ( // <-- children render function
                <LinkContainer
                  icon={<IoApps size={16} />}
                  isActive={isActive} // <-- pass isActive through as prop
                  label="Overview"
                />
              )}
            </NavLink>
    
            <NavLink to="/app">
              {({ isActive }) => (
                <LinkContainer
                  icon={<AiOutlineDashboard size={16} />}
                  isActive={isActive}
                  label="Apps"
                />
              )}
            </NavLink>
          </Stack>
        </Box>
      );
    };
    
    const LinkContainer = ({ icon, isActive, label }) => (
      <Flex
        align="center"
        p="2"
        mx="2"
        borderRadius="lg"
        role="group"
        fontSize="14px"
        cursor="pointer"
        {...(isActive // <-- conditionally apply active props/styling/etc
          ? {
              bg: "#002c8a",
              color: "#fff",
              borderColor: "#002c8a"
            }
          : {})}
        _hover={{
          bg: "#f5f5f5",
          color: "#002c8a",
          borderColor: "#002c8a"
        }}
      >
        <Box
          p="4px"
          border="1px"
          borderRadius="full"
          borderColor="gray.200"
          fontSize="26"
        >
          {icon}
        </Box>
        <Box ml={2} fontSize="sm">
          {label}
        </Box>
      </Flex>
    );
    

    enter image description here