diff --git a/packages/studio-ui/src/components/UndoRedo.tsx b/packages/studio-ui/src/components/UndoRedo.tsx
index eaad55ae5..c64d488ff 100644
--- a/packages/studio-ui/src/components/UndoRedo.tsx
+++ b/packages/studio-ui/src/components/UndoRedo.tsx
@@ -1,6 +1,6 @@
import useTemporalStore from "../store/useTemporalStore";
import { ReactComponent as Undo } from "../icons/undo.svg";
-import { useCallback } from "react";
+import { useCallback, useEffect } from "react";
import classNames from "classnames";
/**
@@ -22,6 +22,17 @@ export default function UndoRedo(): JSX.Element {
redo();
}, [redo]);
+ const handleUndoKeydown = useCallback((event: KeyboardEvent) => {
+ event.preventDefault()
+ if ((event.ctrlKey || event.metaKey) && event.key === "z") {
+ undo()
+ }
+ }, [undo])
+
+ useEffect(() => {
+ document.addEventListener("keydown", handleUndoKeydown)
+ }, [handleUndoKeydown]);
+
const disableUndo = pastStates.length === 0;
const disableRedo = futureStates.length === 0;
const undoClasses = classNames("w-4", {
diff --git a/packages/studio-ui/tests/components/UndoRedo.test.tsx b/packages/studio-ui/tests/components/UndoRedo.test.tsx
index 3e1b6f9cd..50b47860c 100644
--- a/packages/studio-ui/tests/components/UndoRedo.test.tsx
+++ b/packages/studio-ui/tests/components/UndoRedo.test.tsx
@@ -46,6 +46,24 @@ describe("Undo/redo", () => {
expect(useStudioStore.getState().pages.activeComponentUUID).toBeUndefined();
});
+ it("undoes last state update using control + z", async () => {
+ render();
+ expect(useStudioStore.getState().pages.activeComponentUUID).toBe(
+ "searchbar-uuid"
+ );
+ await userEvent.keyboard('{Control>}z{/Control}')
+ expect(useStudioStore.getState().pages.activeComponentUUID).toBeUndefined();
+ });
+
+ it("undoes last state update using command + z", async () => {
+ render();
+ expect(useStudioStore.getState().pages.activeComponentUUID).toBe(
+ "searchbar-uuid"
+ );
+ await userEvent.keyboard('{Meta>}z{/Meta}')
+ expect(useStudioStore.getState().pages.activeComponentUUID).toBeUndefined();
+ });
+
it("redoes single state update when redo is clicked", async () => {
const undo = useTemporalStore((store) => store.undo);
undo();