@gitbook/embed: emit an "escape" event from the frame client
Feature request: emit an escape event from the GitBook embed
Package: @gitbook/embed (observed on v0.5.1)
Area: GitBookFrameClient event protocol (createGitBookFrame)
Summary
Add a dedicated event — e.g. escape — that the embed emits when the user
presses Escape while focus is inside the embed, so the host page can decide
how to respond (typically: close the surrounding panel).
client.on('escape', () => {
// host decides what to do, e.g. close its own panel
});Why the host cannot do this today
We render the embed inside our own dismissible help panel. The embed is served in a cross-origin iframe, which means:
- Keystrokes that happen while focus is inside the iframe are handled by the
embed and never reach the host page. A host-side
keydownlistener forEscapeonly fires while focus is still on the host (i.e. before the user interacts with the embed). Once the search/assistant input is focused, pressing Escape does nothing on our side. - We cannot reach into the iframe (
contentDocumentaccess is blocked) to observe or intercept the key. postMessageis not an option because the embed only honors its own documented protocol.
So there is no host-side workaround for Escape across the cross-origin
boundary. This is unlike focus handling, where iframe.contentWindow.focus()
at least gives the iframe window focus.
Current protocol surface (for reference)
The frame client today exposes:
| Member | Purpose |
|---|---|
navigateToPage |
command |
navigateToAssistant |
command |
postUserMessage |
command |
clearChat |
command |
configure |
command |
on('close', …) |
event — fires when the built-in close button is clicked |
There is an event for the close button, but nothing for Escape, and no way for the host to learn that the user pressed it.
Requested behavior
When the user presses Escape while focus is inside the embed, emit an event the host can subscribe to:
type GitBookFrameClient = {
// ...existing members
on(event: 'escape', listener: () => void): () => void;
};The host stays in control of what happens (close, blur, ignore) — the embed only needs to forward the intent.
Acceptance criteria
- Pressing Escape while the embed (search or assistant input) is focused fires
the
escapeevent on the host's client. - The listener returned unsubscribe function works like the existing
on('close', …)handler. - No change to existing events; this is purely additive.
Use case
A modal-style help panel (search-only, tabs: ['search']) opened from the app
sidebar. Escape should close the panel for keyboard users, consistent with other
modals in the app — including after the user has started typing in search, which
is exactly when the host can no longer see the key.
Notes / alternatives considered
- Embed handles Escape internally and emits the existing
closeevent. Acceptable, but less flexible — some hosts may want to clear input first, or not close at all. A dedicatedescapeevent leaves the policy to the host. - A programmatic
close()command (separate request) would let the host close the embed, but does not solve this issue on its own, because the host still never learns that Escape was pressed inside the iframe.
Source: GitbookIO/gitbook