cyberangles blog

Chakra UI Tooltip Issue: Why It Shows in Top Left Corner Instead of Over Element

Chakra UI has emerged as a favorite among React developers for its accessible, customizable, and developer-friendly components. One of its most commonly used components is the Tooltip—a small pop-up that appears when a user hovers over or focuses on an element, providing additional context. However, a frustrating issue many developers encounter is the tooltip appearing in the top-left corner of the screen (or viewport) instead of positioning itself near the target element.

This problem can break the user experience and leave developers scratching their heads. In this blog, we’ll dive deep into why this happens, explore common causes, and provide step-by-step solutions to fix it. By the end, you’ll have the tools to ensure your Chakra UI tooltips position correctly every time.

2026-01

Table of Contents#

  1. Understanding the Issue: What’s Happening?
  2. Common Causes of Mispositioned Tooltips
  3. Step-by-Step Solutions to Fix the Tooltip
  4. Advanced Troubleshooting
  5. Conclusion
  6. References

1. Understanding the Issue: What’s Happening?#

When a Chakra UI Tooltip appears in the top-left corner, it’s almost always due to a failure in the positioning logic. Chakra UI’s Tooltip component relies on Popper.js (a popular positioning library) under the hood to calculate the tooltip’s position relative to its target element. Popper needs a valid "reference element" (the target the tooltip is attached to) to compute coordinates. If Popper can’t find or access this reference element, it defaults to positioning the tooltip at the origin point (0, 0) of the viewport—hence the top-left corner.

Example Scenario: You wrap a button with a Tooltip, but when you hover over the button, the tooltip appears in the top-left corner instead of above/below/next to the button.

2. Common Causes of Mispositioned Tooltips#

Let’s break down the most likely reasons Popper fails to position the tooltip correctly:

2.1 Missing label Prop#

The label prop is required for the Tooltip component—it defines the content displayed in the tooltip. While omitting label won’t prevent the tooltip from rendering (in some Chakra versions), it can cause the positioning logic to fail. Without content, Popper may not initialize properly, leading to default (0, 0) positioning.

Broken Example:

// ❌ Missing label prop
<Tooltip>
  <Button>Hover Me</Button>
</Tooltip>

2.2 Incorrect Target Element Structure (Multiple Children or Fragments)#

The Tooltip component expects a single child element to act as the target/reference. If you pass multiple children, a React fragment, or a non-element (e.g., a string), Chakra may struggle to identify the reference element. Popper then falls back to (0, 0) because it can’t find a valid bounding box to position against.

Broken Example:

// ❌ Multiple children passed to Tooltip
<Tooltip label="Click to submit">
  <span>Submit</span>
  <Button>Button</Button> {/* Tooltip can't decide which child is the reference */}
</Tooltip>
 
// ❌ Using a fragment
<Tooltip label="Hello">
  <>
    <Button>Hover Me</Button>
  </>
</Tooltip>

2.3 Target Element Not Rendered or Unavailable#

If the target element (the child of Tooltip) is conditionally rendered and hasn’t mounted yet when the tooltip tries to position itself, Popper will have no reference element. This often happens with components that render after an API call or state change.

Broken Example:

// ❌ Target is conditionally rendered and not yet mounted
<Tooltip label="User Profile">
  {userLoaded && <Button>View Profile</Button>} {/* Tooltip mounts before userLoaded is true */}
</Tooltip>

2.4 Parent Element with overflow: hidden or transform#

Popper calculates positioning relative to the viewport by default, but if the tooltip’s parent element has overflow: hidden, the tooltip may be clipped. However, a less obvious issue is parent elements with transform: translateZ(0) or other transform properties. These create a new "stacking context", causing Popper to miscalculate the reference element’s position.

2.5 State Management Issues (isOpen Timing)#

If you manually control the tooltip’s visibility with the isOpen prop (instead of relying on default hover/focus behavior), timing is critical. If isOpen is set to true before the target element mounts, Popper can’t find the reference, leading to (0, 0) positioning.

Broken Example:

// ❌ isOpen is true before the target mounts
const [isOpen, setIsOpen] = useState(true);
 
return (
  <Tooltip label="Tooltip" isOpen={isOpen} onClose={() => setIsOpen(false)}>
    <Button>Hover Me</Button> {/* Tooltip tries to position before Button mounts */}
  </Tooltip>
);

3. Step-by-Step Solutions to Fix the Tooltip#

Now that we’ve identified the causes, let’s fix them with actionable solutions.

3.1 Ensure the label Prop Is Set#

Always include the label prop—it’s required for content and proper initialization.

Fixed Example:

// ✅ label prop is included
<Tooltip label="Click to save changes">
  <Button>Save</Button>
</Tooltip>

3.2 Wrap Target in a Single Element#

The Tooltip must have a single child element (not a fragment or multiple elements). If you need multiple elements, wrap them in a container like Box or div.

Fixed Example:

// ✅ Single child (Box wraps multiple elements)
<Tooltip label="Submit form">
  <Box> {/* Wrapper acts as the reference element */}
    <span>Submit</span>
    <Button>Go</Button>
  </Box>
</Tooltip>

3.3 Avoid Conditional Rendering of the Target Before the Tooltip#

Ensure the Tooltip itself is conditionally rendered only after the target element is ready. This way, the target and tooltip mount together, and Popper can find the reference.

Fixed Example:

// ✅ Tooltip is conditionally rendered with the target
{userLoaded && (
  <Tooltip label="User Profile">
    <Button>View Profile</Button>
  </Tooltip>
)}

3.4 Adjust Parent Element CSS#

If a parent element has overflow: hidden or transform, modify the CSS to avoid clipping or stacking context issues:

  • Remove overflow: hidden from the parent (or use overflow: visible if safe).
  • Avoid unnecessary transform properties on parent elements. If transform is required, use Popper’s modifiers to adjust positioning (see Advanced Troubleshooting).

3.5 Properly Manage isOpen State#

If using isOpen, ensure it’s set to true only after the target element mounts. Use useEffect to delay setting isOpen until the target is available.

Fixed Example:

// ✅ isOpen is set after the target mounts
const [isOpen, setIsOpen] = useState(false);
const targetRef = useRef(null);
 
useEffect(() => {
  // Wait for the target to mount before opening the tooltip
  if (targetRef.current) {
    setIsOpen(true);
  }
}, []);
 
return (
  <Tooltip 
    label="Delayed Tooltip" 
    isOpen={isOpen} 
    onClose={() => setIsOpen(false)}
  >
    <Button ref={targetRef}>Hover Me</Button>
  </Tooltip>
);

4. Advanced Troubleshooting#

If the basic fixes above don’t work, try these advanced strategies:

4.1 Use Popper Directly#

Chakra UI’s Tooltip is a wrapper around the Popper component. If the Tooltip abstraction is causing issues, use Popper directly for more control over positioning:

import { Popper, Box, Button } from '@chakra-ui/react';
 
function CustomTooltip() {
  const [isOpen, setIsOpen] = useState(false);
  const targetRef = useRef(null);
 
  return (
    <>
      <Button 
        ref={targetRef} 
        onMouseEnter={() => setIsOpen(true)} 
        onMouseLeave={() => setIsOpen(false)}
      >
        Hover Me
      </Button>
      
      {isOpen && (
        <Popper placement="top" referenceElement={targetRef.current}>
          {({ placement, transitionProps }) => (
            <Box
              bg="black"
              color="white"
              p={2}
              borderRadius="md"
              {...transitionProps}
            >
              Custom Tooltip Content
            </Box>
          )}
        </Popper>
      )}
    </>
  );
}

4.2 Inspect the DOM and Tooltip Positioning#

Use your browser’s DevTools to:

  • Check if the tooltip is rendered in a portal (Chakra renders tooltips in a portal div at the end of <body> by default).
  • Verify the reference element’s bounding box (use the "Elements" tab to inspect the target element’s getBoundingClientRect()).
  • Look for inline styles on the tooltip (Popper adds top/left styles dynamically—if these are 0px, Popper failed to calculate position).

4.3 Update Chakra UI#

Older versions of Chakra UI had bugs related to Tooltip positioning (e.g., this GitHub issue). Ensure you’re using the latest version:

npm install @chakra-ui/react@latest
# or
yarn add @chakra-ui/react@latest

5. Conclusion#

Chakra UI’s Tooltip appearing in the top-left corner is a common but solvable issue. The root cause is almost always a failure in Popper.js’s positioning logic, typically due to:

  • A missing label prop.
  • An invalid or unavailable reference element (e.g., multiple children, conditional rendering).
  • Parent element CSS interfering with positioning.
  • Prematurely setting isOpen before the target mounts.

By ensuring the target element is a single, rendered element with a valid reference, and managing state/timing correctly, you can resolve this issue and ensure tooltips position reliably.

6. References#