How to Fix VS Code Not Flagging HTML Typos Catching the “oneclick” vs “onclick” Error

I ran into a silly typo that cost me way too much time, I wrote oneclick instead of onclick and VS Code didn’t complain. Nothing happened in the browser, no console error, and I kept staring at the code wondering what on earth I broke. If you’ve been there, this post is exactly what I wish I had read first.

Below, I’ll show the original buggy snippet, explain why VS Code stayed quiet, and then walk through a sturdier, practice-ready refactor that’s easier to maintain, more accessible, and much better at surfacing mistakes. I’ll also add some “try this at home” practice ideas and a final checklist so you don’t get tripped up by this again.

The Original Snippet

<button type="button"
    oneclick="document.getElementById('a').style.visibility='visible'">
  Click
</button>

<img id="a" style="visibility:hidden" src="pico.png" alt="src not found">

What’s The Error

I typed oneclick. The valid HTML event attribute is onclick.

Because oneclick isn’t a recognized attribute, the browser just ignores it. That means no JavaScript runs, and there’s no error it’s perfectly legal (if useless) HTML to the browser.

Why Didn’t VS Code Flag it

I assumed “surely my editor will tell me.” It didn’t here’s why:

  • HTML is permissive. Unknown attributes aren’t illegal; they’re ignored. So linters have to opt into warning you.
  • VS Code’s built-in HTML support isn’t a strict validator. It helps with hints and completions but won’t fail your file for unknown attributes.
  • Common HTML linters don’t warn by default. Tools like HTMLHint often focus on formatting, duplicates, etc. Checking attribute names requires stricter rules or a different validator.

How I Make this Class of Bugs Much Harder to Write

There are two fixes: process and code.

Process Use a Stricter Validator

Install a validator that knows real HTML attributes and will bark at unknown ones:

  • HTML Validate (a.k.a. html-validate) has a VS Code extension and CLI.
  • Turn on rules for unknown attributes so oneclick gets flagged.

Quick start (CLI):

npm i -D html-validate
npx html-validate "**/*.html"

Minimal .htmlvalidate.json:

{
  "extends": ["html-validate:recommended"],
  "rules": {
    "attr-unknown": "error",
    "no-inline-style": "warn",
    "no-inline-event-handler": "warn"
  }
}

With that, oneclick becomes a red, obvious error.

Prefer JS Listeners Over Inline Attributes

Inline onclick is easy to mistype and hard to lint. When I move behavior into JavaScript (addEventListener), I get editor/TypeScript/ESLint help, autocomplete, and real errors for typos like 'clcik'.

My Fix + Enhance Version

This refactor:

  • Removes inline JS (onclick) and uses addEventListener.
  • Uses a .hidden class instead of inline style.
  • Adds Show / Hide / Toggle buttons.
  • Improves accessibility (keyboard + ARIA).
  • Handles image load errors visibly.

Copy this into an index.html and open it in the browser:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <title>Show/Hide Image Practice</title>
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <style>
    .hidden { visibility: hidden; }
    .sr-only {
      position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
      overflow: hidden; clip: rect(0, 0, 1px, 1px); white-space: nowrap; border: 0;
    }
    .toolbar { display: flex; gap: .5rem; margin-bottom: .75rem; }
    button { padding: .5rem .75rem; }
    #status { margin-top: .5rem; color: #b00020; }
  </style>
</head>
<body>
  <h1>Show/Hide Image (Practice)</h1>

  <div class="toolbar" role="group" aria-label="Image visibility controls">
    <button type="button" id="btn-show">Show</button>
    <button type="button" id="btn-hide">Hide</button>
    <button type="button" id="btn-toggle">Toggle</button>
  </div>

  <figure>
    <img id="a" class="hidden" src="pico.png" alt="A small demo image" aria-hidden="true" />
    <figcaption class="sr-only" id="img-caption">Demo image visibility example</figcaption>
  </figure>

  <p id="status" role="status" aria-live="polite"></p>

  <script>
    const img = document.getElementById('a');
    const status = document.getElementById('status');

    const setVisible = (visible) => {
      img.classList.toggle('hidden', !visible);
      img.setAttribute('aria-hidden', String(!visible));
      status.textContent = visible ? 'Image is now visible.' : 'Image is now hidden.';
    };

    document.getElementById('btn-show').addEventListener('click', () => setVisible(true));
    document.getElementById('btn-hide').addEventListener('click', () => setVisible(false));
    document.getElementById('btn-toggle').addEventListener('click', () => {
      const isHidden = img.classList.contains('hidden');
      setVisible(isHidden);
    });

    // Keyboard: press Enter on image to toggle visibility
    img.setAttribute('tabindex', '0');
    img.addEventListener('keydown', (e) => {
      if (e.key === 'Enter') {
        const isHidden = img.classList.contains('hidden');
        setVisible(isHidden);
      }
    });

    // Handle load errors (e.g., wrong src filename)
    img.addEventListener('error', () => {
      setVisible(false);
      status.textContent = 'Could not load the image (check the src path).';
    });
  </script>
</body>
</html>

What I Change

  1. Replaced oneclick/onclick with addEventListener
    • Safer and testable. Editor autocompletes valid event names; TypeScript/ESLint can catch typos.
  2. Swapped inline style for a CSS class
    • .hidden is easier to toggle and keeps structure/behavior/presentation separated.
  3. Added status feedback
    • <p id="status" role="status" aria-live="polite"> announces changes for screen readers and gives me visible feedback for debugging.
  4. ARIA & keyboard support
    • aria-hidden reflects the visual state.
    • tabindex="0" and Enter to toggle helps keyboard users and is great for testing.
  5. Error handling for broken src
    • If pico.png is wrong, I get a clear message instead of guessing.

Make VS Code Actually Complain

If you want the editor to catch these earlier:

HTML Validate extension (or CLI)

  • Install HTML Validate in VS Code.
  • Add .htmlvalidate.json (shown earlier).
  • Reopen your HTML file now oneclick is a real error.

ESLint + TypeScript for JS logic

Even if you keep plain JS, ESLint helps a lot. With TypeScript, typos in event names or DOM IDs get much harder to miss.

Quick start:

npm i -D typescript eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
npx tsc --init

Minimal .eslintrc.json:

{
  "parser": "@typescript-eslint/parser",
  "plugins": ["@typescript-eslint"],
  "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
  "env": { "browser": true, "es6": true }
}

Move your script to main.ts, then compile with tsc. If you mistype 'click' as 'clcik', TypeScript/ESLint will complain.

Practice Drills I Use

  1. Intentional typo drill
    Change id="a" to id="imgA" but forget to update the JS selector once. Watch how your console and linter react.
  2. Visibility vs layout
    Swap .hidden { visibility: hidden; } for .hidden { display: none; }. Notice how layout reflows when the element is removed from the layout.
  3. CSS fade-in/out
    Add a transition for opacity: img { transition: opacity .2s ease; } .hidden { opacity: 0; visibility: hidden; } And toggle both opacity and visibility for smooth animations.
  4. Validator check
    Reintroduce oneclick on purpose and confirm your validator flags it now.
  5. Type-check events
    Convert the script to TypeScript and try addEventListener('clcik', ...). Enjoy the immediate red squiggle.

Final Thought

I blamed VS Code for not yelling at me but the real fix was tightening my toolchain and changing how I write behavior. Browsers are relaxed about unknown attributes, so editors won’t always save me. By moving logic to JavaScript with addEventListener, adding a real HTML validator, and leaning on TypeScript/ESLint, I turned a silent failure into an immediate, obvious error.

Related blog posts