diff --git a/frontend/src/components/ui/CropFrame.dom.test.tsx b/frontend/src/components/ui/CropFrame.dom.test.tsx
index e344bc80..a6b6d33c 100644
--- a/frontend/src/components/ui/CropFrame.dom.test.tsx
+++ b/frontend/src/components/ui/CropFrame.dom.test.tsx
@@ -99,6 +99,24 @@ describe("CropFrame", () => {
expect(rect()).toBe("0.300 0.300 0.400 0.400");
});
+ it("takes the focus on a press, so the arrows go on from where the pointer left it", () => {
+ render();
+ const frame = screen.getByRole("group", { name: "common.cropFrame.frame" });
+ fireEvent.pointerDown(frame, { button: 0, clientX: 500, clientY: 300 });
+ fireEvent.pointerUp(frame, { clientX: 500, clientY: 300 });
+ expect(document.activeElement).toBe(frame);
+ const se = screen.getByRole("group", { name: "common.cropFrame.se" });
+ fireEvent.pointerDown(se, { button: 0, clientX: 960, clientY: 540 });
+ expect(document.activeElement).toBe(se);
+ // An edge is the pointer's only: its press puts the focus on the frame it belongs to.
+ fireEvent.pointerDown(document.querySelector(".cursor-ew-resize")!, {
+ button: 0,
+ clientX: 960,
+ clientY: 400,
+ });
+ expect(document.activeElement).toBe(frame);
+ });
+
it("lets a press outside the frame through to the player, and keeps one on the frame", () => {
const click = vi.fn();
render(
diff --git a/frontend/src/components/ui/CropFrame.tsx b/frontend/src/components/ui/CropFrame.tsx
index 460f7c04..c377ccdc 100644
--- a/frontend/src/components/ui/CropFrame.tsx
+++ b/frontend/src/components/ui/CropFrame.tsx
@@ -90,6 +90,9 @@ export function CropFrame({ aspect, rect, ratio, onChange, className }: Props) {
// The press is the frame's: not the video's play / pause, not a scrub of anything under it.
e.stopPropagation();
e.preventDefault();
+ // preventDefault also stops the press from focusing: focused by hand, so the arrows go on from
+ // here (an edge is the pointer's only, so its frame takes the focus).
+ e.currentTarget.closest("[tabindex]")?.focus({ preventScroll: true });
try {
e.currentTarget.setPointerCapture(e.pointerId);
} catch {