DEV Community

Muhammad Omer Baig
Muhammad Omer Baig

Posted on

React + Tailwind Design Issue: Dynamic Arrow Alignment Outside Buttons

current design - red box highlights the alignment issue

desired design

I'm working on a React project using Tailwind CSS. My buttons feature arrows (<-) positioned outside, aligned towards the center of the button's right border with some space between them. Currently:

Buttons with shorter text display arrows correctly. Longer text causes arrows to misalign, disrupting the design. Design Flow:

Arrows (<-) are positioned outside each button. They should align dynamically to the center of the right border of the button, maintaining a consistent visual distance.

Challenge: How can I adjust arrow alignment dynamically in React with Tailwind CSS, ensuring they stay centered along the right edge of buttons regardless of text length? I need to preserve the space between buttons and arrows as part of the design.

Here’s the relevant code for button component and arrow alignment:

import DiscoveryButton from '../DiscoveryButton/DiscoveryButton';

const RightSection = ({ responses, activeResponse, handleButtonClick }) => {
  return (
    <div className="grid grid-cols-[80%_20%] relative">
    {/* Button Grid */}
    <div className="grid grid-cols-1 items-start  space-y-4">
      {responses.map((response, index) => (
        <DiscoveryButton
          key={index}
          index={index}
          active={activeResponse === index}
          onClick={handleButtonClick}
        />
      ))}
    </div>

    {/* Navigation Arrows */}
    <div className="grid grid-cols-1 mt-2 pl-2  justify-center relative">
      {responses.map((response, index) => (
        // VERTICAL LINE HERE
        <div
          key={index}
          className="relative w-full pt-[--pt] bg-[image:linear-gradient(#000,#000),linear-gradient(#000,#000)] bg-[position:0_calc((theme(fontSize.base.1.lineHeight)*.5)-1px+var(--pt)),100%_var(--y,0%)] bg-[length:100%_2px,2px_var(--h,100%)] bg-no-repeat [--pt:theme(padding.4)] first:[--pt:0%] first:[--y:calc(theme(fontSize.base.1.lineHeight)*.5)] last:[--h:calc((theme(fontSize.base.1.lineHeight)*.5)+var(--pt))]"
        >
          {/* Poistioning of Arrow head */}
          <svg
            className="translate-y-[calc((theme(fontSize.base.1.lineHeight)-24px)*.75)]"
            width="16.8"
            height="24"
            viewBox="0 0 16.8 24"
            fill="none"
          >
            {/* ARROW HEAD HERE */}
            <path
              d="M0 12l12 12 1.4-1.4L4.2 12 13.4 3.4 10 0l-12 12z"
              fill="currentColor"
            />
          </svg>
          {/* for the line passing through the 3rd arrow */}
          {index === 2 && (
            <div class="absolute left-full top-[--pt] h-[2px] bg-black w-5 mt-[11px]" />
          )}
        </div>
      ))}
    </div>
    </div>
  );
};

export default RightSection;

Enter fullscreen mode Exit fullscreen mode
// DiscoveryButton.jsx

import React from 'react';
import { buttonNames } from './buttonNames';

const DiscoveryButton = ({ index, active, onClick }) => {
  return (
    <button
      onClick={() => onClick(index)}
      className={`px-4 py-2.5 text-lg  text-right ${active ? 'bg-theme-blue text-white rounded-lg ' : 'bg-transparent text-black'}`}
    >
      {buttonNames[index]}
    </button>
  );
};

export default DiscoveryButton;

Enter fullscreen mode Exit fullscreen mode
import { useState } from 'react';
import Heading from '../Heading/Heading';
import LeftSection from './sections/LeftSection';
import CenterSection from './sections/CenterSection';
import RightSection from './sections/RightSection';
import { responses } from './discoveryResponses'; // Adjust path as necessary
import { buttonNames } from './DiscoveryButton/buttonNames';
import { theme } from '../../theme';

const DiscoveryResponse = () => {
  const [activeResponse, setActiveResponse] = useState(0);

  const handleButtonClick = (index) => {
    setActiveResponse(index);
  };

  return (
    <section className={`${theme.padding.mobileVertical} ${theme.padding.mobileHorizontal} ${theme.padding.mediumHorizontal}`}>


      <div className="text-center pt-4 pb-8">
        <Heading
          title="Discovery Response Generator (Discovery Workflow)"
          titleFirst={true}
          boldText="(Discovery Workflow)"
          titleFontSize='text-40px'
        />
      </div>

      {/* Parent Grid Container */}
      <div className="grid grid-cols-1 md:grid-cols-[30%_35%_35%] py-10 gap-10">

        {/* Left Section (Image Display) */}
        <LeftSection imageSrc={responses[activeResponse].image} />

        {/* Center Section (Text Display) */}
        <CenterSection
          buttonName={buttonNames[activeResponse]}
          responseText={responses[activeResponse].text}
        />

        {/* Right Section (Button Grid and Navigation Arrows) */}
        <RightSection
          responses={responses}
          activeResponse={activeResponse}
          handleButtonClick={handleButtonClick}
        />
      </div>
    </section>
  );
};

export default DiscoveryResponse;

Enter fullscreen mode Exit fullscreen mode

Top comments (0)