Skip to content

Input and Change Events

Click events cover buttons and links. Form controls need a different set of events: input fires as the user types, change fires when a value is committed, and keydown/keyup capture individual key presses.

input fires on every keystroke in a text field or textarea — it is the real-time event:

const nameField = document.querySelector('#name');
nameField.addEventListener('input', (event) => {
console.log(event.target.value); // current field value after the keystroke
});

event.target.value always holds the current string in the field. This is how you build live feedback: character counts, live search filtering, instant validation.

change fires when the element loses focus (for text inputs) or when the value changes (for checkboxes, radios, and selects). It does not fire on every keystroke:

const categorySelect = document.querySelector('#category');
categorySelect.addEventListener('change', (event) => {
console.log('Selected:', event.target.value);
});

Use input for text fields when you want real-time feedback. Use change for selects and checkboxes where “on every character” does not apply.

keydown fires when a key is pressed, keyup when it is released. Use event.key to identify which key:

const searchField = document.querySelector('#search');
searchField.addEventListener('keydown', (event) => {
if (event.key === 'Enter') {
console.log('Search submitted:', event.target.value);
}
if (event.key === 'Escape') {
searchField.value = '';
}
});

Common key names: 'Enter', 'Escape', 'Tab', 'ArrowUp', 'ArrowDown', ' ' (space), 'Backspace'. Single characters are their literal character: 'a', 'A', '1'.

event.key — the logical key value, respects the keyboard layout and modifiers. 'A' with Shift held.
event.code — the physical key on the keyboard regardless of layout. 'KeyA' always.

Prefer event.key for most text interaction. Use event.code only when you need physical key location (like WASD game controls).

For checkboxes, use event.target.checked (a boolean) instead of event.target.value:

const availableCheckbox = document.querySelector('#show-available');
availableCheckbox.addEventListener('change', (event) => {
const showOnlyAvailable = event.target.checked;
console.log('Filter available only:', showOnlyAvailable);
});

Add a character counter to the STO contact form message textarea. As the user types, show how many characters they have entered:

const messageField = document.querySelector('#contact-message');
const charCount = document.querySelector('.char-count');
if (messageField && charCount) {
const limit = 500;
function updateCharCount(length) {
charCount.textContent = `${length} / ${limit}`;
charCount.classList.toggle('over-limit', length > limit);
}
updateCharCount(messageField.value.length);
messageField.addEventListener('input', (event) => {
updateCharCount(event.target.value.length);
});
}

The updateCharCount call before the listener handles a browser quirk: browsers restore textarea values after a page refresh, but the counter HTML starts at 0 characters. Calling updateCharCount on load syncs the display with whatever is already in the field.

Add this after the textarea in contact.html:

<span class="char-count">0 characters</span>

Add these styles to styles.css in the form section:

.char-count {
display: block;
font-size: 0.875rem;
color: var(--color-text-muted);
margin-top: var(--space-xs);
}
.char-count.over-limit {
color: var(--color-error);
font-weight: 600;
}

You will also need to add --color-error: #b91c1c; to the :root variable block in styles.css if it is not already defined.

Type in the field, then refresh the page — the counter should reflect the restored value immediately.

  • input fires on every keystroke — use for real-time feedback. event.target.value holds the current string.
  • change fires on blur (for text fields) or value change (for selects, checkboxes) — not every character.
  • keydown/keyup + event.key capture specific key presses like 'Enter' and 'Escape'.
  • For checkboxes, use event.target.checked (boolean), not event.target.value.
  • event.key gives the logical character; event.code gives the physical key — prefer event.key for text interactions.