{"id":13400585,"url":"https://github.com/glortho/react-keydown","last_synced_at":"2026-02-06T15:08:15.923Z","repository":{"id":1631955,"uuid":"43563194","full_name":"glortho/react-keydown","owner":"glortho","description":"Lightweight keydown wrapper for React components","archived":false,"fork":false,"pushed_at":"2023-03-01T09:50:55.000Z","size":8499,"stargazers_count":498,"open_issues_count":17,"forks_count":35,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-10-24T00:01:20.820Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://glortho.github.io/react-keydown/example/index.html","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/glortho.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2015-10-02T16:16:39.000Z","updated_at":"2025-09-14T17:23:11.000Z","dependencies_parsed_at":"2023-07-09T17:17:41.992Z","dependency_job_id":null,"html_url":"https://github.com/glortho/react-keydown","commit_stats":{"total_commits":333,"total_committers":17,"mean_commits":19.58823529411765,"dds":0.4774774774774775,"last_synced_commit":"28d0d8d5ffd5476427907d97754a81f905cc8dfa"},"previous_names":["jedverity/react-keydown"],"tags_count":64,"template":false,"template_full_name":null,"purl":"pkg:github/glortho/react-keydown","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glortho%2Freact-keydown","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glortho%2Freact-keydown/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glortho%2Freact-keydown/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glortho%2Freact-keydown/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/glortho","download_url":"https://codeload.github.com/glortho/react-keydown/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glortho%2Freact-keydown/sbom","scorecard":{"id":430207,"data":{"date":"2025-08-11","repo":{"name":"github.com/glortho/react-keydown","commit":"28d0d8d5ffd5476427907d97754a81f905cc8dfa"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.7,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/2 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 28 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"40 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-cwfw-4gq5-mrqx","Warn: Project is vulnerable to: GHSA-g95f-p29q-9xw4","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-x9w5-v3q2-3rhw","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c","Warn: Project is vulnerable to: GHSA-w573-4hg7-7wgq","Warn: Project is vulnerable to: GHSA-h6ch-v84p-w6p9","Warn: Project is vulnerable to: GHSA-434g-2637-qmqr","Warn: Project is vulnerable to: GHSA-49q7-c7j4-3p7m","Warn: Project is vulnerable to: GHSA-977x-g7h5-7qgw","Warn: Project is vulnerable to: GHSA-f7q4-pwc6-w24p","Warn: Project is vulnerable to: GHSA-fc9h-whq2-v747","Warn: Project is vulnerable to: GHSA-vjh7-7g9h-fjfh","Warn: Project is vulnerable to: GHSA-8r6j-v8pm-fqw3","Warn: Project is vulnerable to: MAL-2023-462","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-6c8f-qphg-qjgp","Warn: Project is vulnerable to: GHSA-76p3-8jx3-jpfq","Warn: Project is vulnerable to: GHSA-3rfm-jhwj-7488","Warn: Project is vulnerable to: GHSA-hhq3-ff78-jv3g","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-r683-j2x4-v87g","Warn: Project is vulnerable to: GHSA-h7cp-r72f-jxh6","Warn: Project is vulnerable to: GHSA-v62p-rq8g-8h59","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-h9rv-jmmf-4pgx","Warn: Project is vulnerable to: GHSA-hxcc-f52p-wc94","Warn: Project is vulnerable to: GHSA-f5x3-32g6-xq36","Warn: Project is vulnerable to: GHSA-4wf5-vphf-c2xc","Warn: Project is vulnerable to: GHSA-52f5-9888-hmc6","Warn: Project is vulnerable to: GHSA-7p7h-4mm5-852v","Warn: Project is vulnerable to: GHSA-fhg7-m89q-25r3","Warn: Project is vulnerable to: GHSA-p9pc-299p-vxgp"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-19T03:09:49.884Z","repository_id":1631955,"created_at":"2025-08-19T03:09:49.884Z","updated_at":"2025-08-19T03:09:49.884Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29165914,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-06T14:37:12.680Z","status":"ssl_error","status_checked_at":"2026-02-06T14:36:22.973Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-30T19:00:53.588Z","updated_at":"2026-02-06T15:08:15.907Z","avatar_url":"https://github.com/glortho.png","language":"JavaScript","readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"http://glortho.github.io/react-keydown/example/index.html\" target=\"_blank\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/glortho/react-keydown/master/example/public/react-keydown-logo.png\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n[![npm version](https://badge.fury.io/js/react-keydown.svg)](https://badge.fury.io/js/react-keydown)\n[![dependencies](https://david-dm.org/glortho/react-keydown.svg)](https://david-dm.org/glortho/react-keydown.svg)\n\nUse react-keydown as a higher-order component or decorator to pass keydown\nevents to the wrapped component, or call methods directly via designated keys. Good\nfor implementing keyboard navigation or other shortcuts.\n\nKey advantages:\n\n* **Declarative syntax**: Components say what keys they will respond to.\n* **Intuitive DX**: Decorate a class or method to bind it to specified keys.\n* **Scoping**: Designate the scope of your bindings by decorating/wrapping components. Only those components and their children will receive the designated key events, and then only when they appear to be active.\n* **Modifier keys**: Support for standard modifier key combinations.\n* **Lightweight**: 2kb compressed and gzipped, and only attaches a single keydown listener to document, no matter how many keybindings you specify.\n* **Cross-browser**: Works in all browsers except IE 8 and below.\n\nConsult the [API \u0026 Reference Documentation](https://github.com/jedverity/react-keydown/wiki/API-\u0026-Reference) or continue reading below for quick start.\n\n**NOTE**: react-keydown doesn't use decorators itself, but to use the `@keydown` pattern in your application you will need a transpiler like Babel and a decorator transform plugin like this: https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy.\n\n## Install\n\n```\nnpm install --save react-keydown\n```\n\n## Use\n\nThe default build of react-keydown uses the CommonJS module system. For\nAMD or other support, use the [umd-specific\nbranch](https://github.com/jedverity/react-keydown/tree/master-umd) instead.\n\n### For methods: Decorate with keys that should trigger method\n\n```javascript\nimport React from 'react';\nimport keydown from 'react-keydown';\n\nclass MyComponent extends React.Component {\n\n  @keydown( 'enter' ) // or specify `which` code directly, in this case 13\n  submit( event ) {\n    // do something, or not, with the keydown event, maybe event.preventDefault()\n    MyApi.post( this.state );\n  }\n}\n```\n\nNote: Since the only context we have for keydown events is the component, decorated methods receive the event as their sole argument and the component instance as context.\n\n#### Specify multiple keys that should trigger the method\n\n```javascript\nimport keydown, { Keys } from 'react-keydown';\n\nconst { ENTER, TAB } = Keys; // optionally get key codes from Keys lib to check against later\n\n@keydown( ENTER, TAB, 'ctrl+z' ) // could also be an array\nautocomplete( event ) {\n  if ( event.which === ENTER ) { ... }\n  MyApi.get( this.state );\n}\n```\n\n### For classes: Pass keydown events into your component\n\n```javascript\n@keydown\nclass MyComponent extends React.Component {\n  componentWillReceiveProps( { keydown } ) {\n    if ( keydown.event ) {\n      // inspect the keydown event and decide what to do\n      console.log( keydown.event.which );\n    }\n  }\n\n  render() {\n    return (\n      \u003cdiv\u003ekeydown events will only get passed down after this DOM node mounts or is clicked on\u003c/div\u003e\n    );\n  }\n}\n\nexport default MyComponent;\n```\n\n#### Monitor only key codes `which` you care about:\n\n```javascript\nconst KEYS = [ 'shift+up', 'shift+down', 'enter', 'j', 'k', 'h', 'l' ];\n\n@keydown( KEYS )\nclass MyComponent extends React.Component {\n  ...\n}\n```\n\n#### Use the `@keydownScoped` shortcut\n\nWhen using the class decorator/higher-order component, decorate methods with `@keydownScoped` to identify the `keydown.event` prop as it comes in and bind certain values to methods:\n\n```javascript\nimport keydown, { keydownScoped } from 'react-keydown';\n\n@keydown( 'enter' ) // optional to specify a key here. if called with just @keydown, all key events will get passed down\nclass MyComponent extends React.Component {\n  render() {\n    return \u003cMyOtherComponent {...this.props} /\u003e;\n  }\n}\n\nclass MyOtherComponent extends React.Component {\n  ...\n  @keydownScoped( 'enter' ) // inspects nextProps.keydown.event in componentWillReceiveProps behind the scenes\n  submit() {\n    // submit\n  }\n}\n```\n\nThis is a convenience method, but also lets you specify a larger view context where this key binding should be active. Sometimes the component where the binding is declared is too small on its own.\n\nThis can also be a good way to set up app-wide shortcuts. Wrap your root component with `@keydown` and then use  `@keydownScoped` or manually inspect the `keydown.event` props in the child components where those bindings are relevant.\n\n### Handling all keys\n\nIn some cases you might want to handle all keys on your own. For that, you can specify the following:\n\n```\nimport keydown, { ALL_KEYS } from 'react-keydown'\n\n@keydown( ALL_KEYS )\nhandleKeys(ev) {\n  // handle keys here\n}\n```\n\n### Handling all printable keys\n\nAnother useful feature is handling all printable characters.\n\n```\nimport keydown, { ALL_PRINTABLE_KEYS } from 'react-keydown'\n\n@keydown( ALL_PRINTABLE_KEYS )\nbeginEdit(ev) {\n  // Start editing\n}\n```\n\n### Caveat: Input, textarea, and select elements\n\nBy default, bindings will not work when these fields have focus, in order not to interfere with user input and shortcuts related to these controls. You can override this in two ways:\n\n1. Give your shortcut a `ctrl` modifier.\n\n2. Since v1.6.0, there is experimental support for adding an `onKeyDown` binding to the element, specifying a method decorated with `@keydown` as the handler. For example:\n\n```javascript\nclass MyClass extends React.Component {\n\n  @keydown( 'a' )\n  myMethod( event ) {\n    console.log( event ); // should log only on 'a' keystroke, whether input is focused or not\n  }\n\n  render() {\n    return \u003cinput onKeyDown={ this.myMethod } /\u003e;\n  }\n}\n```\n\nIn the second case you could make multiple inputs work this way by spreading `{ onKeyDown: this.myMethod }` into them, or by making this a reusable input component that takes the method as a prop (or composes multiple methods passed in as props).\n\n## Demo\n\nGo to the [live\ndemo](http://glortho.github.io/react-keydown/example/index.html) or:\n\n```\n$ open example/public/index.html\n```\n\nNote that this is very much a work in progress!\n\n## Test\n\n```\n$ npm test\n```\n\n\n## Notes, disclaimers, and tips\n\n* The decorator pattern `@keydown` currently requires transpilation by\n  the [Babel legacy decorators transform](https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy) or the equivalent.\n* Components that have a [React 16 fragment](https://reactjs.org/docs/fragments.html) at their root may not be activated properly when clicked. See [this issue](https://github.com/glortho/react-keydown/issues/80) for more detail.\n* The default build outputs CommonJS modules and native ES modules. For AMD or other support, use the\n  [umd-specific\n  branch](https://github.com/glortho/react-keydown/tree/master-umd) instead.\n* This lib has only been tested using ES2015 classes and class methods. Some method decoration\n  functionality may work on other types of object methods.\n* Duplicate keybindings for components that are mounted at the same time will\n  not both fire. The more recently mounted component, or the one that has been\n  focused or clicked most recently, will win. If you do want both to fire,\n  decorate a common ancestor class with `@keydown( ... )` and then use\n  `@keydownScoped( ... )` in the child components (or just inspect\n  `nextProps.keydown.event` in both).\n* Since the only context we have for keydown events is the component, decorated\n  methods receive the event as their sole argument and the component instance as\n  context.\n* The method decorators wrap React lifecycle methods in order to work\n  as seamlessly and efficiently as possible. The class decorator does not do\n  this, functioning instead as a higher-order component.\n\n## Questions\n\nWhy is this so limited, only working on `keydown` and such?\n\n\u003e I published this out of my particular need on a project. If anyone else ever\narrives here and needs something else let me know via issues or a pull request.\n\n","funding_links":[],"categories":["UI Utilities","Uncategorized","UI Components","UI Utilites","React [🔝](#readme)"],"sub_categories":["Device Input","Uncategorized","Device Input/User Action"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fglortho%2Freact-keydown","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fglortho%2Freact-keydown","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fglortho%2Freact-keydown/lists"}