I am using react hooks for the tab components. I need to show the border line below the active tab item. This works only after clicking the tab item. It does not work initially. I am using ref to get the element of the active tab item but its not working. Here is how i have done

const Tabs = ({ activeTab, children }) => {
  const [tabElements, setTabElements] = useState({});
  const tabsElements = useRef({});
  useEffect(() => {
    console.log("ref", tabsElements);
    setTabElements(prevState => ({
  }, []);
  return (
    <TabsContext.TabProvider activeTab={activeTab}>
        {value => (
                {value.context.tabs.map(tab => (
                    ref={tabElement => {
                      tabsElements.current[tab.id] = tabElement;
                    isActiveTab={value.context.activeTab.id === tab.id}
              <pre>{JSON.stringify(tabElements, null, 2)}</pre>
                  tabElements.current !== undefined &&


here is the codesandbox of it either


How do i show the border line just below the active tab item?

1 Answers

Shubham Khatri On Best Solutions

The solution to the above requires modifying your strategy a bit. Instead of having an ActiveTabBorder component which takes the ref and render the result based on the elements position, we add the style for border within the TabTitleItem itself with a :after pseudo element and style it a little differently using display: flex

Your Styled components will look like below

export const ListTabs = styled.ul`
  padding-left: 0;
  list-style: none;
  margin: 0;
  display: flex;
  justify-content: center;

export const TabTitleItem = styled.li`
  position: relative;
  transition: all 800ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
  padding: 16px 30px;
  cursor: pointer;
  opacity: 0.4;
  display: flex;
  flex-direction: column;
  align-items: center;
  ${props =>
    props.isActiveTab &&
        transition: all 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
        cursor: default;
        opacity: 1;

       &:after {
        content: '';
        height: 5px;
        background-color: blue;
        position: absolute;
        bottom: 0;
        transition: all 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
        width: 100%;


Working demo