Skip to main content

useEscapeKey

BetaSince 0.1.0

Calls a function when Escape is pressed, so Esc closes only the topmost of several popups.

import { useEscapeKey } from "@anantya/uix";

Overview

useEscapeKey calls a function when the reader presses Escape. When several are enabled, only the one enabled last runs, so Esc closes the topmost popup and leaves the rest open. UIX components use it to close popups, such as Dialog. In product code, use it to cancel something in progress, such as an export.

Building block

For a popup, use Dialog, or Popover or Dropdown Menu, coming in v1, which close on Esc already.

Missing a component? Ask for it instead of building your own.

Signature

function useEscapeKey(
handler: (event: KeyboardEvent) => void,
options?: UseEscapeKeyOptions,
): void;

interface UseEscapeKeyOptions {
enabled?: boolean;
}

Parameters

ParameterTypeDefaultDescription
handler(event: KeyboardEvent) => void-Called with the keydown event of the Escape key.
options.enabledbooleantrueListens while true, such as while a popup is open or an export runs.

Returns

Nothing. It listens while enabled is true and stops when it turns false or the component unmounts.

Example

While the export runs, Esc cancels it and announces "Export cancelled". The text under the button says so, too.

Exports every invoice from this year.

Code
"use client";

import { announce, Button, useEscapeKey } from "@anantya/uix";
import { useEffect, useState } from "react";

const messages = {
idle: "Exports every invoice from this year.",
exporting: "Press Esc to cancel.",
ready: "Export ready: invoices-2026.csv",
cancelled: "Export cancelled.",
};

export default function CancelExport() {
const [state, setState] = useState<keyof typeof messages>("idle");
const exporting = state === "exporting";

useEffect(() => {
if (!exporting) return;
const timer = setTimeout(() => {
setState("ready");
announce("Export ready");
}, 5000);
return () => clearTimeout(timer);
}, [exporting]);

useEscapeKey(
() => {
setState("cancelled");
announce("Export cancelled");
},
{ enabled: exporting },
);

return (
<div className="flex flex-col items-center gap-2 text-sm">
<Button loading={exporting} loadingText="Exporting…" onClick={() => setState("exporting")}>
Export invoices
</Button>
<p className="text-muted-foreground">{messages[state]}</p>
</div>
);
}

Notes

  • Say on screen that Esc works, as the example does: nothing else tells the reader
  • When the handler removes the focused element, move focus somewhere sensible, so keyboard users don't lose their place
  • It calls preventDefault() on the press before your handler, so the same press closes nothing else, such as a Dialog under the popup
  • A press already handled with preventDefault(), or made while typing with an input method, such as for Hindi or Japanese, is ignored
  • It does nothing on the server

Changelog

Every change to useEscapeKey since 0.1.0 is in the release notes.

© Anantya TechLabs. All rights reserved.