Junior Web Developer study materials
Junior Web Developer study resources

Junior Web Developer common mistakes

Junior Web Developer · Understand the traps and how to avoid them.

Mistake 1

Using divs and spans for everything (buttons, navigation, headers) instead of the appropriate semantic element, then adding ARIA roles to compensate.

Candidates learn layout with generic containers first and reach for div by habit; they also assume ARIA can substitute for native semantics, not realizing native elements come with keyboard behavior and accessibility semantics built in.

What to do instead

Before writing a container, ask what the content is: use header, nav, main, section with a heading, article, aside, footer for structure; use button for actions and a for navigation. Only add a role when no native element fits, and never add a role that duplicates what the element already implies.

Mistake 2

Building layouts with fixed pixel widths and absolute positioning, then having the page overflow horizontally or collapse on narrow viewports.

Candidates design at one screen size and verify only there; fixed widths feel predictable, and absolute positioning seems to give exact control until content grows or the viewport shrinks.

What to do instead

Default to normal flow with Flexbox or Grid, use max-width instead of width for content columns, use relative units and min()/clamp() for sizing, and test by resizing the viewport and zooming to 200%. Reserve absolute positioning for overlays and decorative placement, not page structure.

Mistake 3

Confusing var, let, and const scoping and hoisting, or assuming a function declared inside a block is available outside it.

All three declarations look interchangeable in simple examples, and hoisting is invisible until a variable is read before its declaration line. Candidates memorize 'const means constant' without learning that it blocks reassignment of the binding, not mutation of an object.

What to do instead

Use const by default, let when reassignment is needed, and avoid var. Learn the mechanics: let/const are block-scoped and in a temporal dead zone until initialized; var is function-scoped and initialized to undefined. Practice predicting output for loops with closures and for reads before declaration.

Mistake 4

Attaching event listeners to elements that do not exist yet, or adding a new listener every time a handler runs, causing duplicate firing or memory growth.

Scripts placed in head run before the DOM is parsed, so querySelector returns null; and candidates who re-render list items often re-bind handlers on each render without removing old ones.

What to do instead

Place scripts at the end of body or use the DOMContentLoaded event (or defer on the script tag). For dynamic content, use event delegation: one listener on a stable ancestor that checks event.target.closest(selector). When re-rendering, remove listeners or rebuild nodes so handlers are not stacked.

Mistake 5

Treating accessibility as a checklist of attributes, adding alt text like 'image' or 'click here' for links, and skipping keyboard testing entirely.

Candidates add attributes to satisfy a linter without understanding the user experience; they never navigate their own page with Tab and Enter, so focus order and invisible focus styles go unnoticed.

What to do instead

Write alt text that conveys the image's purpose, or alt="" for decorative images. Make link text meaningful out of context. Test the page using only the keyboard: every interactive element must be reachable, show a visible focus indicator, and activate with Enter or Space. Check color contrast against WCAG AA ratios.

Mistake 6

Submitting a form with the default GET method when it changes data, or failing to call preventDefault in a JavaScript submit handler so the page reloads and state is lost.

GET is the default and works fine for search boxes, so candidates never switch it; and a submit handler that fetches data still lets the browser perform its native navigation unless the default is cancelled.

What to do instead

Use method="post" for anything that creates, updates, or deletes data; reserve GET for safe, idempotent reads. In a JS submit handler, call event.preventDefault() before your logic, and always give inputs a label and a name attribute so values are submitted.

Mistake 7

Committing secrets, node_modules, or generated files, and working directly on main with vague commit messages like 'fix' or 'update'.

Candidates are not taught to inspect git status before committing, and early tutorials initialize repos without a .gitignore. Working solo makes branching feel unnecessary until a mistake needs reverting.

What to do instead

Create a .gitignore before the first commit and run git status and git diff --staged before every commit. Write messages that state what changed and why. Use a feature branch per task, and never commit API keys; if one is committed, rotate it rather than only deleting it, since history retains it.

Mistake 8

Inserting user-supplied content with innerHTML, or building SQL or shell commands by string concatenation with user input.

innerHTML is the shortest way to render HTML and works in demos where input is trusted. Candidates do not see the attack because they never test with a payload like a script tag or an event-handler attribute.

What to do instead

Render untrusted text with textContent or element.textContent, or build nodes with createElement and set attributes explicitly. Sanitize only if HTML is genuinely required. On the server, use parameterized queries and avoid interpolating input into commands; treat all client input as hostile and validate on the server.

Mistake 9

Debugging by guessing and editing code repeatedly instead of using the browser devtools: no breakpoints, no console inspection, no reading of the actual error message and stack trace.

Candidates are used to print-style debugging and find devtools intimidating; they also misread errors, treating a TypeError on null as a problem with the line above rather than the missing element.

What to do instead

Reproduce the bug, read the full error and stack trace, then set a breakpoint in the Sources panel and step through, inspecting variables at each frame. Use console.log sparingly for state, and check the Network panel for failed requests. Write a failing test first when the bug is logic-related.

Mistake 10

Writing tests that assert on implementation details or timing (exact call counts, fixed setTimeout delays) so they pass locally and fail intermittently in CI.

Candidates test what is easy to observe rather than what the user experiences, and asynchronous code is hard to await correctly, so they insert arbitrary delays that race under load.

What to do instead

Assert on observable behavior and output, not internal calls. For async work, await the promise or use your framework's async utilities and wait for a condition (element appearing, request resolving) rather than a fixed delay. Run the suite repeatedly to surface flakiness before trusting a green run.