---
title: Hotkeys
image: /images/user-guide/table-views/table.png
---

<Frame>
  <img src="/images/user-guide/table-views/table.png" alt="Header" />
</Frame>

## Inleiding

Wanneer jy na 'n sleutelkombinasie moet luister, sou jy normaalweg die `onKeyDown` gebeurtenis luisteraar gebruik.

In `twenty-front` kan jy egter konflik hê tussen dieselfde sleutelkombinasies wat in verskillende komponente gebruik word, wat terselfdertyd gemonteer is.

Byvoorbeeld, as jy 'n bladsy het wat na die Enter-sleutel luister, en 'n modale wat na die Enter-sleutel luister, met 'n Kies-komponent binne-in daardie modaal wat na die Enter-sleutel luister, kan jy 'n konflik hê wanneer alles gelyktydig gemonteer is.

## Die `useScopedHotkeys` hook

Om hierdie probleem te hanteer, het ons 'n persoonlike hook wat dit moontlik maak om na sleutelkombinasies te luister sonder enige konflik.

Jy plaas dit in 'n komponent, en dit sal slegs na die sleutelkombinasies luister wanneer die komponent gemonteer is EN wanneer die gespesifiseerde **sleutelkombinasie-omvang** aktief is.

## How to listen for hotkeys in practice?

There are two steps involved in setting up hotkey listening :

1. Stel die [sleutelkombinasie-omvang](#what-is-a-hotkey-scope-) wat na sleutelkombinasies sal luister op
2. Gebruik die `useScopedHotkeys` hook om na sleutelkombinasies te luister

Setting up hotkey scopes is required even in simple pages, because other UI elements like left menu or command menu might also listen to hotkeys.

## Use cases for hotkeys

In general, you'll have two use cases that require hotkeys :

1. In a page or a component mounted in a page
2. In a modal-type component that takes the focus due to a user action

The second use case can happen recursively : a dropdown in a modal for example.

### Listening to hotkeys in a page

Voorbeeld :

```tsx
const PageListeningEnter = () => {
  const {
    setHotkeyScopeAndMemorizePreviousScope,
    goBackToPreviousHotkeyScope,
  } = usePreviousHotkeyScope();

  // 1. Set the hotkey scope in a useEffect
  useEffect(() => {
    setHotkeyScopeAndMemorizePreviousScope(
      ExampleHotkeyScopes.ExampleEnterPage,
    );

    // Revert to the previous hotkey scope when the component is unmounted
    return () => {
      goBackToPreviousHotkeyScope();
    };
  }, [goBackToPreviousHotkeyScope, setHotkeyScopeAndMemorizePreviousScope]);

  // 2. Use the useScopedHotkeys hook
  useScopedHotkeys(
    Key.Enter,
    () => {
      // Some logic executed on this page when the user presses Enter
      // ...
    },
    ExampleHotkeyScopes.ExampleEnterPage,
  );

  return <div>My page that listens for Enter</div>;
};
```

### Listening to hotkeys in a modal-type component

For this example we'll use a modal component that listens for the Escape key to tell its parent to close it.

Here the user interaction is changing the scope.

```tsx
const ExamplePageWithModal = () => {
  const [showModal, setShowModal] = useState(false);

  const {
    setHotkeyScopeAndMemorizePreviousScope,
    goBackToPreviousHotkeyScope,
  } = usePreviousHotkeyScope();

  const handleOpenModalClick = () => {
    // 1. Set the hotkey scope when user opens the modal
    setShowModal(true);
    setHotkeyScopeAndMemorizePreviousScope(
      ExampleHotkeyScopes.ExampleModal,
    );
  };

  const handleModalClose = () => {
    // 1. Revert to the previous hotkey scope when the modal is closed
    setShowModal(false);
    goBackToPreviousHotkeyScope();
  };

  return <div>
    <h1>My page with a modal</h1>
    <button onClick={handleOpenModalClick}>Open modal</button>
    {showModal && <MyModalComponent onClose={handleModalClose} />}
  </div>;
};
```

Dan in die modale komponent :

```tsx
const MyDropdownComponent = ({ onClose }: { onClose: () => void }) => {
  // 2. Use the useScopedHotkeys hook to listen for Escape.
  // Note that escape is a common hotkey that could be used by many other components
  // So it's important to use a hotkey scope to avoid conflicts
  useScopedHotkeys(
    Key.Escape,
    () => {
      onClose()
    },
    ExampleHotkeyScopes.ExampleModal,
  );

  return <div>My modal component</div>;
};
```

It's important to use this pattern when you're not sure that just using a useEffect with mount/unmount will be enough to avoid conflicts.

Those conflicts can be hard to debug, and it might happen more often than not with useEffects.

## Wat is 'n sleutelkombinasie-omvang?

'n Sleutelkombinasie-omvang is 'n string wat 'n konteks verteenwoordig waarin die sleutelkombinasies aktief is. It is generally encoded as an enum.

Wanneer jy die sleutelkombinasie-omvang verander, word die sleutelkombinasies wat na hierdie omvang luister geaktiveer en die sleutelkombinasies wat na ander omvang luister, gedeaktiveer.

Jy kan net een omvang op 'n slag stel.

As an example, the hotkey scopes for each page are defined in the `PageHotkeyScope` enum:

```tsx
export enum PageHotkeyScope {
  Settings = 'settings',
  CreateWorkspace = 'create-workspace',
  SignInUp = 'sign-in-up',
  CreateProfile = 'create-profile',
  PlanRequired = 'plan-required',
  ShowPage = 'show-page',
  PersonShowPage = 'person-show-page',
  CompanyShowPage = 'company-show-page',
  CompaniesPage = 'companies-page',
  PeoplePage = 'people-page',
  OpportunitiesPage = 'opportunities-page',
  ProfilePage = 'profile-page',
  WorkspaceMemberPage = 'workspace-member-page',
  TaskPage = 'task-page',
}
```

Intern word die tans geselekteerde omvang gestoor in 'n Recoil-toestand wat oor die aansoek gedeel word :

```tsx
export const currentHotkeyScopeState = createState<HotkeyScope>({
  key: 'currentHotkeyScopeState',
  defaultValue: INITIAL_HOTKEYS_SCOPE,
});
```

Maar hierdie Recoil-toestand moet nooit met die hand hanteer word nie! Ons sal sien hoe om dit in die volgende afdeling te gebruik.

## Hoe werk dit intern?

We made a thin wrapper on top of [react-hotkeys-hook](https://react-hotkeys-hook.vercel.app/docs/intro) that makes it more performant and avoids unnecessary re-renders.

We also create a Recoil state to handle the hotkey scope state and make it available everywhere in the application.