Как сделать стрелку указывающую на активный элемент

Как сделать стрелку указывающую на активный элемент чтобы при изменении активного элемента стрелка передвигалась к нему

введите сюда описание изображения

export const GeolocationHead = () => {
const cities = ['Москва', 'Санкт-Петербург']; 
const [activeIndex, setActiveIndex] = useState<number>(0); 
const [hoverIndex, setHoverIndex] = useState<number | null>(null);

const handleMouseEnter = (index: number): void => {
    setHoverIndex(index); 
};

const handleMouseLeave = (): void => {
    setHoverIndex(null);
};

const handleButtonClick = (index: number): void => {
    setActiveIndex(index);
};

return (
    <div className={styles['geolocation__head']}>
        <div className={styles['geolocation__head-title']}>
            <p className={styles['geolocation__head-title--main']}>Работаем</p>
            <p className={styles['geolocation__head-title--sub']}>по всей стране</p>
        </div>

        <div className={styles['geolocation__head-button']}>
            <p>Выберите интересующий шоурум:</p>
            {cities.map((city, index) => {
                const isActive = activeIndex === index; 
                const isHovered = hoverIndex === index; 

                return (
                    <button
                        key={index}
                        className={`
                            ${styles['btn']} 
                            ${isHovered ? styles['hovered'] : ''} 
                            ${isActive && hoverIndex === null ? styles['active'] : ''}
                        `}
                        onClick={() => handleButtonClick(index)}
                        onMouseEnter={() => handleMouseEnter(index)} 
                        onMouseLeave={handleMouseLeave}
                    >
                        {city}
                    </button>
                );
            })}
        </div>
    </div>
);

};

export const GeolocationMap = () => {
return (
    <div className={styles['geolocation__map']}>
        <iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d577332.5658670563!2d36.726216496938264!3d55.58103355220319!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x46b54afc73d4b0c9%3A0x3d44d6cc5757cf4c!2z0JzQvtGB0LrQstCwLCDQoNC-0YHRltGP!5e0!3m2!1suk!2sua!4v1729377229655!5m2!1suk!2sua" width="600" height="450" style={{ border: 0 }} allowFullScreen loading="lazy" referrerPolicy="no-referrer-when-downgrade"></iframe>

        <div className={styles['geolocation__map-info']}>
            <div className={styles['geolocation__map-info-column']}>
                <p className={styles['geolocation__map-info-street']}><b>Москва <br /> ул. Тимирязевская, д. 1, стр. 2</b></p>
                <p className={styles['geolocation__map-info-phone']}><b>+7 (929) 590 82-87</b></p>
            </div>

            <div className={styles['geolocation__map-info-column']}>
                <div className={styles['geolocation__map-info-gmail']}>
                    <a href="">[email protected]</a> 
                    <p>По вопросам сотрудничества</p>               
                </div>

                <div className={styles['geolocation__map-info-social']}>
                    <p>Подписывайтесь на наши соц.сети:</p>

                    
                </div>
            </div>
        </div>
    </div>
);

};

.geolocation__map{
display: grid;
grid-template-columns: 1fr 1fr;
border: 1px solid #E2AE80;
border-radius: 30px;
padding: 40px;

Ответы (2 шт):

Автор решения: Andrei Fedorov

Чисто визуальная история - вам нужно добавить для кнопки псевдоэлемент (стрелку), которая визуально будет являться декором для контентного блока. Только не забудьте что размеры отступа между кнопками и контентным блококом теперь имеет значение.

Вот модельный код:

.navigation {
  display: flex;
  justify-content: flex-end;
  gap: .4em;
  margin-bottom: 1em;
}

.content {
  padding: 2em;
  border: .1em solid #777;
  border-radius: 1em;
}

.button {
  font: inherit;
  padding: .8em 1.6em;
  border: .1em solid #777;
  border-radius: .2em;
  position: relative;
  &:hover::after {
    content: '';
    position: absolute;
    left: 50%;
    bottom: -1.6em;
    width: 1em;
    height: 1em;
    border: .1em solid #777;
    border-right: none;
    border-bottom: none;
    transform: rotate(45deg);
    translate: -50% 0;
    background-color: white;
    z-index: 10;
  }
}

*,
*::after,
*::before {
  box-sizing: border-box;
}

body {
  font-size: 200%;
  margin: 1em;
}


}
<div class="wrapper">
  <div class="navigation">
    <button class="button">Lorem</button>
    <button class="button">Ipsum</button>
  </div>
  <div class="content">
    Lorem ipsum dolor, sit amet consectetur adipisicing elit. Laboriosam soluta, illo aut veritatis ea nam vitae quidem et consequuntur temporibus error similique nesciunt impedit iusto molestias accusantium vel cupiditate delectus perspiciatis officiis ipsum
    repellendus? Perspiciatis veritatis quos eveniet ex aspernatur dicta, aut culpa, sed dignissimos tenetur corrupti earum cupiditate accusantium itaque. Officiis dolor doloribus natus dolores. At ex, saepe nam unde laborum consequuntur quaerat magni
    blanditiis voluptatum consectetur asperiores molestiae mollitia hic quo vel voluptate autem voluptates cumque, iure inventore numquam delectus! Qui laborum quia eius nostrum alias inventore impedit repellat, similique tempora repellendus veritatis
    nam ut ratione debitis possimus.
  </div>
</div>

→ Ссылка
Автор решения: lukaschuk O

вот решение:

const buttons = document.querySelectorAll('.button');
const navigation = document.querySelector('.navigation');

let arrow = document.querySelector('.arrow');
if (!arrow) {
  arrow = document.createElement('div');
  arrow.classList.add('arrow');
  navigation.appendChild(arrow);
}

const moveArrow = (button) => {
  const buttonRect = button.getBoundingClientRect();
  const navigationRect = navigation.getBoundingClientRect();

  arrow.style.left = `${buttonRect.left - navigationRect.left + buttonRect.width / 2}px`;
};

buttons.forEach(button => {
  button.addEventListener('click', () => {
    buttons.forEach(btn => btn.classList.remove('active'));

    button.classList.add('active');

    moveArrow(button);
  });
});

moveArrow(document.querySelector('.button.active'));

window.addEventListener('resize', () => {
  const activeButton = document.querySelector('.button.active');
  if (activeButton) {
    moveArrow(activeButton);
  }
});
*,
*::after,
*::before {
  box-sizing: border-box;
}

body {
  font-size: 200%;
  margin: 1em;
}

.navigation {
  display: flex;
  justify-content: flex-end;
  gap: .4em;
  margin-bottom: 1em;
  position: relative;
}

.content {
  padding: 2em;
  border: .1em solid #777;
  border-radius: 1em;
}

.button {
  font: inherit;
  padding: .8em 1.6em;
  border: .1em solid #777;
  border-radius: .2em;
  position: relative;
  cursor: pointer;
}

.active {
  background-color: #e49999;
}

.arrow {
  position: absolute;
  bottom: -1.54em;
  width: 1em;
  height: 1em;
  border: .1em solid #777;
  border-right: none;
  border-bottom: none;
  transform: rotate(45deg);
  background-color: white;
  z-index: 10;
  transition: left 0.3s ease;
  left: 50%;
  transform: translateX(-50%) rotate(45deg);
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="style.css">
</head>

<body>
  <div class="wrapper">
    <div class="navigation">
      <button class="button active">Lorem</button>
      <button class="button">Ipsum</button>
      <div class="arrow"></div>
    </div>
    <div class="content">
      Lorem ipsum dolor, sit amet consectetur adipisicing elit. Laboriosam soluta, illo aut veritatis ea nam vitae quidem et consequuntur temporibus error similique nesciunt impedit iusto molestias accusantium vel cupiditate delectus perspiciatis officiis ipsum
      repellendus? Perspiciatis veritatis quos eveniet ex aspernatur dicta, aut culpa, sed dignissimos tenetur corrupti earum cupiditate accusantium itaque. Officiis dolor doloribus natus dolores. At ex, saepe nam unde laborum consequuntur quaerat magni
      blanditiis voluptatum consectetur asperiores molestiae mollitia hic quo vel voluptate autem voluptates cumque, iure inventore numquam delectus! Qui laborum quia eius nostrum alias inventore impedit repellat, similique tempora repellendus veritatis
      nam ut ratione debitis possimus.
    </div>
  </div>
</body>

</html>

→ Ссылка