HextaUI

useHeldKeys

As teclas que alguém está segurando agora, compartilhadas por todos os assinantes por meio de um único conjunto de listeners na janela.

Hold down any keys
[]
"use client"

import { Kbd, KbdGroup } from "@/components/ui/kbd"
import { useHeldKeys } from "@/hooks/use-held-keys"

export function UseHeldKeysDemo() {
  const held = useHeldKeys(true)

  return (
    <div className="flex flex-col items-center gap-3">
      <div className="flex h-8 items-center">
        {held.size > 0 ? (
          <KbdGroup>
            {[...held].map((key) => (
              <Kbd key={key} keys={key} size="lg" />
            ))}
          </KbdGroup>
        ) : (
          <span className="text-sm text-muted-foreground">
            Hold down any keys
          </span>
        )}
      </div>
      <code className="font-mono text-xs text-muted-foreground">
        {JSON.stringify([...held])}
      </code>
    </div>
  )
}
pnpm dlx shadcn@latest add https://hextaui.com/r/use-held-keys.json

Adiciona o hook e tudo de que ele depende ao seu projeto.

import { useHeldKeys } from "@/hooks/use-held-keys"
const held = useHeldKeys(true)
const showShortcutHints = held.has("meta") || held.has("ctrl")

Use para qualquer coisa que reaja a teclas seguradas em vez de pressionadas: teclas que afundam, dicas de atalho que aparecem enquanto você segura ⌘, ou um modificador que troca uma ferramenta, como Alt para duplicar ao arrastar.

Todo componente que chama o hook compartilha um único store. O primeiro assinante adiciona listeners passivos de keydown e keyup em window, e o último a cancelar a assinatura os remove. Uma página com cinquenta teclas escutando ainda tem um par de listeners.

Os listeners apenas leem eventos. Nunca chamam preventDefault e ficam em window, depois dos handlers do próprio React, então digitar em um campo nunca é atrasado nem alterado.

"meta" "ctrl" "alt" "shift"     modifiers, left and right alike
"a" … "z"  "0" … "9"            letters and digits, by physical key
"space" "enter" "escape" "tab"   named keys, lowercased
"arrowup" "arrowdown" "f1" …
  • Letras e dígitos vêm de event.code, a tecla física, então segurar Option+K em um Mac ainda informa k em vez de ˚.
  • A repetição de tecla é ignorada, e nada é renderizado novamente enquanto uma tecla está segurada.
  • O macOS não envia keyup para outras teclas enquanto ⌘ está pressionada. Quando ⌘ é solta, o store mantém apenas os modificadores ainda segurados, para letras não ficarem presas.
  • Tudo é liberado quando a janela perde o foco ou a aba fica oculta. Um atalho que troca de app não deixa nada preso.

Teclas que pressionam

<Kbd listen> é construído sobre este hook. Cada tecla é pressionada enquanto sua tecla real está segurada.

"use client"

import { Kbd, KbdGroup } from "@/components/ui/kbd"
import { useHeldKeys } from "@/hooks/use-held-keys"
import { useIsApple } from "@/lib/hotkey"

export function UseHeldKeysShortcut() {
  const held = useHeldKeys(true)
  const apple = useIsApple()
  const modifier = apple ? "meta" : "ctrl"
  const ready = held.has(modifier) && held.has("shift")

  return (
    <div className="flex flex-col items-center gap-3 text-sm">
      <KbdGroup>
        <Kbd keys="mod" listen />
        <Kbd keys="shift" listen />
        <Kbd keys="p" listen />
      </KbdGroup>
      <p className="text-muted-foreground">
        {ready ? "Now press P" : "Hold the modifiers to see the hint"}
      </p>
    </div>
  )
}
  • Passe false para parar de escutar. O hook então retorna um conjunto vazio e não adiciona listeners, então é barato chamá-lo incondicionalmente.
  • O conjunto só é substituído quando uma tecla é pressionada ou solta, então sua identidade funciona como dependência de memo ou effect.
  • Para atalhos que disparam uma ação, use matchesHotkey de Hotkey em um handler de keydown. Segurar teclas serve para mostrar estado, não para executar comandos.
  • No servidor, e antes da hidratação, o conjunto está vazio.
PropTipoPadrão
enabledSe deve escutar. Quando false, nada é anexado.
boolean–
RetornaDescrição
ReadonlySet<string>Os nomes das teclas seguradas agora.

Kbd e KbdGroup por meio da sua prop listen.