PreviewTrigger popover renders unpositioned in the top-left corner after a fast sweep across several triggers

Đã đóng
#10,680 5 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
3/5
Thời gian dự kiến
1-2 ngày
Mức phù hợp với người mới
66/100
Loại issue
Lỗi
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
react, typescript
Lĩnh vực
frontend

Hướng nghiên cứu

Start with the PreviewTrigger and useOverlayPosition entry points, then reproduce the issue with the minimal PreviewTrigger example while sweeping across triggers with a real mouse. Trace the warm-up path and positioning update, and consider the issue done when the popover never renders unpositioned or remains open after the trigger interaction ends.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

waiting
Provide a general summary of the issue here

Right after one PreviewTrigger preview has closed, sweeping the pointer quickly across several other triggers can open the next preview unpositioned: it renders in the top-left corner of the viewport (position: fixed; top: 0; left: 0, no data-placement) until its trigger is hovered again. Reproduced with a bare PreviewTrigger in react-aria-components 1.21.1; a screen recording and a minimal reproduction are below.

🤔 Expected Behavior?

A PreviewTrigger popover only renders once it is positioned next to its trigger, or not at all.

😯 Current Behavior

After one preview has just closed, sweeping the pointer quickly across several PreviewTriggers and stopping just beside the last one sometimes opens that trigger's popover unpositioned:

  • It renders at position: fixed; top: 0; left: 0 (the fallback style from useOverlayPosition when it has no position yet), with no data-placement.
  • It stays in the corner until its trigger is hovered again, and then jumps into place.
  • Occasionally it doesn't close at all until the trigger is hovered again.

It only reproduces with a real mouse. Synthetic pointer events (user-event, and PointerEvents dispatched by script) didn't reproduce it in our tests. A screen recording is attached.

💁 Possible Solution

A guess: the warm-up path (the next preview opens immediately while warm, with shouldSkipAnimation) seems to open the popover in a way where updatePosition doesn't run, or bails out, until the trigger fires hover events again.

As a workaround we hide the popover until it has a placement:

:not([data-placement]) { visibility: hidden; }
🔦 Context

We use PreviewTrigger for info icons in a list of statistics rows, one trigger per row. Moving the mouse down the list is enough to hit it now and then.

Side note: PreviewTrigger replaces its trigger's style prop (with its own WebkitUserDrag / WebkitTouchCallout) instead of merging it, so inline styles on the trigger Button are silently dropped. That's why the reproduction styles the button with a class.

🖥️ Steps to Reproduce
import { Button, Popover, PreviewTrigger } from "react-aria-components";

function Row({ label }: { label: string }) {
  return (
    <div style={{ display: "flex", justifyContent: "space-between", width: 240 }}>
      <span>{label}</span>
      <PreviewTrigger delay={300}>
        <Button aria-label={label} className="repro-trigger">i</Button>
        <Popover
          aria-label={label}
          offset={10}
          style={{ background: "#111827", color: "white", padding: 12, width: 220 }}
        >
          <strong>{label}</strong>
          <ul>
            <li><a href="#a" style={{ color: "white" }}>First link</a></li>
            <li><a href="#b" style={{ color: "white" }}>Second link</a></li>
          </ul>
        </Popover>
      </PreviewTrigger>
    </div>
  );
}

export function App() {
  return (
    <div style={{ display: "grid", gap: 4, padding: "120px 0 0 400px" }}>
      <style>
        {".repro-trigger { width: 24px; height: 24px; background: #e5e7eb; border: 1px solid #9ca3af; border-radius: 4px; }"}
      </style>
      {["Row 1", "Row 2", "Row 3", "Row 4", "Row 5", "Row 6"].map((label) => (
        <Row key={label} label={label} />
      ))}
    </div>
  );
}
  1. Hover a trigger until its preview opens, then move away so it closes.
  2. Straight after, sweep the pointer quickly down over the next few triggers (about 70ms on each), and stop just below the last one, not on it.
  3. Sometimes the last trigger's popover appears in the top-left corner of the viewport. Hovering that trigger again moves it into place.

It may take a few tries.

https://github.com/user-attachments/assets/017b07c0-968b-493e-b561-5ae95bccba42

Version

react-aria-components 1.21.1 (react-aria 3.52.1, react 19.2.7)

What browsers are you seeing the problem on?

Chrome

If other, please specify.

No response

What operating system are you using?

macOS 27.0

🧢 Your Company/Team

No response

🕷 Tracking Issue

No response

Ngôn ngữ chính
TypeScript
Star
16k
Fork
1.6k
Merge trung bình
3 ngày 19 giờ
Pull request đã merge (30 ngày)
46

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của adobe/react-spectrum

Tất cả issue của adobe/react-spectrum

Issue tương tự

Thêm issue về TypeScript

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.