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.
The input event
Section titled “The input event”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.
The change event
Section titled “The change event”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 and keyup
Section titled “keydown and keyup”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 vs event.code
Section titled “event.key vs event.code”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).
Checkboxes
Section titled “Checkboxes”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);});STO capstone: live character counter
Section titled “STO capstone: live character counter”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.
inputfires on every keystroke — use for real-time feedback.event.target.valueholds the current string.changefires on blur (for text fields) or value change (for selects, checkboxes) — not every character.keydown/keyup+event.keycapture specific key presses like'Enter'and'Escape'.- For checkboxes, use
event.target.checked(boolean), notevent.target.value. event.keygives the logical character;event.codegives the physical key — preferevent.keyfor text interactions.