8. Interactivity 2. `Keydown` event handling. Active key state
Tags: webdev, javascript, beginners, tutorial
Published: 2022-08-18 05:42:35

---
published: true
title: 8. Interactivity 2. `Keydown` event handling. Active key state
tags: webdev, javascript, beginners, tutorial
cover_image: https://res.cloudinary.com/practicaldev/image/fetch/s--2Ycgb9E_--/c_imagga_scale,f_auto,fl_progressive,h_420,q_auto,w_1000/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t7manuew9dwi5jlrf8p5.png
series: keyboard-learning-app
published_at: '2022-08-18T05:42:35Z'
---

- [`Keydown` event handling](#keydown-event-handling)
  - [`activeKey` state](#activekey-state)
  - [Operational System (OS) language](#operational-system-os-language)
  - [Active key styling](#active-key-styling)
  - [Fade active key after a while](#fade-active-key-after-a-while)

## `Keydown` event handling

In the file `Keyboard.js` add to `mounted()` an event listener on `keydown`:

```javascript
	mounted() {
		this.getKeyboardData(this.currentLang)

		/* add: */
		window.addEventListener('keydown', event => {
			e.preventDefault()
			console.log(event)
		})
	},
```

Save the file.

Open Chrome dev tools tab `console`. Click with mouse on the app to make the window active to catch events from it. Press random keys on the (physical) keyboard. Events will appear in a console.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dpwd3fmyfx917t2y6vg7.gif)

Experiment with different keys and see results. Expand `KeyboardEvent` and look at its properties. We need only 3 of them: `code`, `key`, and `shiftKey`.

Close console (Dev tools).

[Diffs in code 8.1](https://github.com/ApayRus/keyboard/commit/3c24e6d130ac4d8ac06aecf95b9979e1f70e7166)

### `activeKey` state

In `Keyboard.js` `data()` add a new state `activeKey`. It will be filled with `{ code, key, shiftKey }` from the `event`. Add `activeKey` to template to see how it will be changed.

Keyboard.js

```js
import Key from './Key.js'

const Keyboard = {
	template: `
	<div>activeKey: {{activeKey}}</div>
	<div class="keyboard">
		<div
			v-for="(row, index) in keyboardData"
			:class="['row', 'row-'+(index+1)]"
		>
			<vue-key
				v-for="keyContent in row"
				:keyContent="keyContent"
			/>
		</div>
	</div>`,
	components: {
		'vue-key': Key
	},
	data() {
		return {
			keyboardData: [],
			/* add: */
			activeKey: { code: '' }
		}
	},
	props: {
		currentLang: String
	},
	watch: {
		currentLang: function (currentLang) {
			this.getKeyboardData(currentLang)
		}
	},
	mounted() {
		this.getKeyboardData(this.currentLang)

		window.addEventListener('keydown', event => {
			event.preventDefault()
			/* add: (read particular props of event) */
			const { code, key, shiftKey } = event
			/* write event parts to the state: */
			this.activeKey = { code, key, shiftKey }
		})
	},

	methods: {
		async getKeyboardData(lang) {
			const { default: keyboardData } = await import(
				`../keyboardData/${lang}.js`
			)
			this.keyboardData = keyboardData
		}
	}
}

export default Keyboard
```

Press `q, w` in all lang layouts (`en`, `ru`, `ar`).

Result:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rhzp0eh8cjmk2wf10rw8.gif)

### Operational System (OS) language

You see, that the same events happen with any `currentLang`. That's because our web app state is not connected with OS language (for keyboard). And there is no technical ability to do this.

If a user switches a language in OS (alt+shift, ctrl+shift), an event property `key` will be different, but our app wont know what language is set in OS.

Anyway `code` is always the same. That's why we made it the required identifier in the `data model`.

### Active key styling

In `Keyboard.js` pass state `activeKey` as a prop to `Key`. And warn the `Key` about the new prop.

Keyboard.js template:

```html
<vue-key ... :activeKey="activeKey" />
```

Key.js props:

```js
props: {
	...
	activeKey: Object,
}
```

Now we can use `activeKey` inside the `Key` component to apply conditional styling to one of the keys (the active one).

Key.js template:

replace

```html
<div class="key">
	<div class="main">{{main}}</div>
	<div class="shifted">{{shifted}}</div>
</div>
```

with:

```html
<div
	:class="[
			'key', 
			{active: activeKey.code === keyContent.code}
			]"
>
	<div class="main">{{main}}</div>
	<div class="shifted">{{shifted}}</div>
</div>
```

Now `:class` is dynamic (calculated, variable).

Style `key` will be applied to a button (key) in any case.

Style `active` will be applied only if key `code` is the same as the code of the `activeKey`. If you remember, we added `.key.active` style to `styles.css` in chapter 2.

Result:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mztq823b7ecmx6f9ukmf.gif)

It works with any language, and doesn't depend on a system language for the keyboard.

### Fade active key after a while

There is a problem. If we press a button, and then don't press anything, `activeKey` stays forever. But we want it to fade after a while.

In `Keyboard.js` in `addEventListener`:

after

```javascript
this.activeKey = { code, key, shiftKey }
```

add

```javascript
setTimeout(() => (this.activeKey = { code: '' }), 1000)
```

That means, that after 1000 milliseconds (1 sec), `activeState` will be cleared.

Result:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pykv58hm0zjxvxfjiwgv.gif)

Looking good, the active key automatically disappears after 1 sec.

But there is another problem. When we type fast several keys in 1 sec, only one timer works, that started after pressing the first button. If we type `1, 2, 3, 4, 5` in 900 milliseconds, `5` will disappear after 100 milliseconds, which is incorrect.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bzc58ahzoso2hhh8j7n2.gif)

We respect `5` (as any other key) and will give to it the whole 1 second. To do that we need to store a particular `timeout` when key pressed, and if another key is pressed before timeout ended, we'll clear old `timeout` and create a new one. That will guarantee 1 sec for any key.

App.js

replace

```js
setTimeout(() => (this.activeKey = { code: '' }), 1000)
```

with

```javascript
/* if there was old timeout, we clear it*/
clearTimeout(this.timeout)
/* store a new timeout for the last pressed key */
this.timeout = setTimeout(() => (this.activeKey = { code: '' }), 1000)
```

Now `5` also has 1 sec to show itself to the world:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dm7r3j8jvcm34emdg3mn.gif)

[Diffs in code 8.2](https://github.com/ApayRus/keyboard/commit/f5ab71548fd5bdc5e05d6c09af8e7bc38165c59b)

[Entire code after the chapter](https://github.com/ApayRus/keyboard/tree/8.-Interactivity-2.-Keydown-event-handling.-Active-key-state)