0

I have a navbar component as shown below with a bunch of tabs that are displayed dynamically depending on how many components the developer passes in to Navbar.js. If the amount of tabs overflow, it is automatically hidden and cut off from the fixed width of the parent div component. Now I want to add an arrowLeft and arrowRight component that lets the user click to scroll to show the hidden tabs. How would I go about this? I'm really hoping for a solution without the need of jquery.

Navbar.js

import React, { useState } from 'react';
import Tab from './Tab';
import Filter from './Filter';
import { StyledTabs, NavbarOutline, arrowLeft, arrowRight } from '../styledComponents/StyledNavbar';

const Navbar = ({ value, tabFilter, contentFilter }) => {
  const [activeTab, setActiveTab] = useState(value[0].title);

  const onClickTabItem = tab => {
    setActiveTab(tab);
  }

  return (
    <React.Fragment>
      <NavbarOutline>
        <ol>
          <arrowLeft />
        </ol>
        <ol>
          {value.map(child => {
            const { title } = child;
            return <Tab activeTab={activeTab} key={title} title={title} handleClick={onClickTabItem} />;
          })}
        </ol>
        <ol>
          {tabFilter && !contentFilter && <Filter key="tabFilter" tab />}
          {contentFilter && !tabFilter && <Filter key="contentFilter" content />}
          <arrowRight />
        </ol>
      </NavbarOutline>
      <div>
        {value.map(child => {
          if (child.title !== activeTab) return undefined;
          return <StyledTabs className="content">{child.title}</StyledTabs>
        })}
      </div>
    </React.Fragment>
  );
}

export default Navbar;

StyledNavbar.js (styled-components)

import styled from 'styled-components';

export const NavbarOutline = styled.div`
  margin-left: 35px;
  margin-right: 35px;
  overflow-x: auto;
  white-space: nowrap;
  top: 0px;
  -ms-overflow-style: none;  /* Internet Explorer 10+ */
  scrollbar-width: none;  /* Firefox */
  &::-webkit-scrollbar { 
    display: none; /* Safari and Chrome */
  }
`;

export const StyledTabs = styled.button.attrs(props => ({
  className: props.className,
}))`
  &.not-active {
    font-style: normal;
    font-weight: normal;
    font-size: 16px;
    line-height: 20px;
    list-style: none;
    padding: 16px 31px 16px 31px;
    background: none;
    border: none;
    border-bottom: 2px solid #e3e3e3;
    z-index: -1;
  }
  &.active {
    font-style: normal;
    font-weight: normal;
    font-size: 16px;
    line-height: 20px;
    list-style: none;
    margin-bottom: -2px;
    padding: 16px 31px 16px 31px;
    background: none;
    border: none;
    color: #2b8000;
    border-bottom: 3px solid #2b8000;
    z-index: -1;
  }
  &.content {
    list-style: none;
    background: none;
    border: none;
    margin-left: 35px;
    margin-right: 35px;
  }
  &.filter {
    font-style: normal;
    font-weight: normal;
    font-size: 16px;
    line-height: 20px;
    list-style: none;
    position: relative;
    padding: 16px 31px 16px 31px;
    border: none;
    border-bottom: 2px solid #e3e3e3;
    display: block;
    margin-top: -54px;
    background: white;
    right: 0px;
  }
`;
1

1 Answer 1

2

What you are looking for is called an intersectionObserver. There's a native DOM API, but I recommend going with the react-intersection-observer package. It's well maintained and documented.

You'll want to use the useInView hook to create refs for every DOM node you want to keep track of, and use the parent component as root for them. Then you show the arrows conditionally depending on which refs' inView === true.

To scroll you can use the native scrollIntoView() API, or use a react package for that as well.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.