Frontend Engineering
Building the part of a system a person operates directly: the browser as a runtime with its own scheduling and rendering rules, state and component architecture at the point where senior work actually lives, performance measured against real devices, and accessibility as both a craft and a legal obligation.
Assumes you know: JavaScript beyond syntax, including closures and asynchronous execution, HTML and CSS well enough to build a page without a framework, HTTP basics, including status codes, caching headers and what a request costs
Overview
What this area actually covers
Frontend engineering is building software that runs on a machine you do not own, over a network you cannot predict, for a person who is holding it. Nearly everyone underestimates the scope, because the visible output is a screen and the screen looks simple.
Four things sit underneath. The browser as a runtime: a single-threaded JavaScript execution model with its own task scheduling, a document tree that is expensive to mutate, an event system, several incompatible storage options, and a security model built on origins. Rendering and performance: the pipeline from markup and stylesheets to pixels, and what it costs to disturb it on a mid-range phone rather than your laptop. State and component architecture: deciding what data exists, who owns it, when it is stale, and how a change propagates without the application becoming a web of implicit dependencies. Accessibility: making the interface operable by keyboard, by screen reader, and by someone who cannot perceive colour or hold a pointer steady.
What gets wrongly bundled in is mostly design. Choosing typography, spacing and colour is design work; implementing it faithfully across viewports is frontend work, and the two are related but not the same skill. Nor is frontend simply "React", which is one answer to a subset of the problem. Treating the framework as the discipline is the commonest reason a candidate who has shipped for three years cannot explain why their page is slow.
The nine topics underneath
The section is split into nine topics, and the split follows how frontend interviews are actually structured rather than how a curriculum would organise it. Three topics are language and type system, three are framework, and three are the platform beneath all of them. The last group is the part that keeps its value longest.
| Topic | What it is for |
|---|---|
| JavaScript Core | The language semantics every frontend screen opens with |
| TypeScript | Expressing component and data contracts so the compiler enforces them |
| React | The dominant framework, and the reasoning its model demands |
| Angular & Vue | The other two mainstream models, with different reactivity assumptions |
| Browser & Rendering | The runtime itself, which every framework sits on top of |
| Web Performance | Measuring what a user experiences and fixing the specific cause |
| CSS & Layout | Making a layout hold under real content on real viewports |
| Accessibility | Making the interface operable by everyone, and passing an audit |
| Frontend System Design | Architecting a client application rather than a component |
JavaScript Core is where nearly every frontend interview begins, and it goes deeper than the syntax. Closures and why a variable captured in a loop behaves as it does, the event loop and the ordering guarantees between a promise callback and a timer, prototypes and how property lookup really resolves, coercion and the small set of rules that explain the notorious comparisons, and the async semantics that make the difference between code that works and code that works most of the time. It exists first because every other topic assumes it.
TypeScript is treated separately because its type system is unusual enough to be its own subject. Structural typing means compatibility is decided by shape rather than by declared inheritance, which surprises people arriving from nominal languages. Generics, narrowing through control flow, discriminated unions for modelling states that cannot coexist, and the utility types that let you derive one contract from another are the recurring content. In interviews it usually appears as "type this component's props correctly", which is a design question wearing a syntax costume.
React gets its own topic because it is the framework most jobs use and because its model has specific, gradeable consequences. Reconciliation and why keys matter, the rules of hooks and why they exist, dependency arrays and the class of bugs a wrong one produces, when a re-render is a problem and when it is not, server components and the boundary they draw between what runs where, and the choice between local state, context and an external store. The questions have moved over time from lifecycle trivia to correctness of effects and data flow.
Angular & Vue cover the two other mainstream models, and they are worth understanding even if you use neither, because they make the reactivity trade-off explicit. Angular's dependency injection and change detection, and Vue's reactive primitives, solve the same problems React solves with different defaults, and being able to compare the approaches is the fastest way to demonstrate that you understand the problem rather than one solution to it. If the role uses one of them, expect framework-specific lifecycle and module questions.
Browser & Rendering is the platform topic and the one that ages best. The critical rendering path from bytes to pixels, the difference between a reflow and a repaint and which operations trigger which, event capturing and bubbling and why delegation works, the storage options and their differing lifetimes and size limits, and how cookies behave across origins. Everything a framework does eventually reduces to operations described here, which is why senior interviews spend disproportionate time on it.
Web Performance is measurement first and optimisation second. The topic covers Core Web Vitals — Largest Contentful Paint, Cumulative Layout Shift and Interaction to Next Paint, which replaced First Input Delay as a Core Web Vital in March 2024 — along with bundle splitting, image strategy, font loading and the distinction between laboratory and field data. Its central discipline is refusing to guess: you measure, you find the specific cause, you fix it, and you measure again, and a candidate who describes that loop scores above one who lists techniques.
CSS & Layout is underrated by candidates and is a common source of quiet failure in practical exercises. The cascade and how specificity resolves a conflict, flexbox and grid and which problem each is for, stacking contexts and why a z-index that ought to work does not, containing blocks and how position interacts with transforms, and a responsive strategy that survives text scaled up and content longer than the design assumed. It is a separate topic because the failure mode is not ignorance but half-knowledge that holds until something unusual happens.
Accessibility covers semantics first, then interaction, then the standard. Native elements and the behaviour they bring for free, keyboard operability and focus management, ARIA and the specific ways it is misused, and the WCAG success criteria that come up in review and procurement. It is its own topic rather than a footnote on components because a large part of it is process — how you test, with what, and at what point in the workflow — rather than knowledge of individual attributes.
Frontend System Design is the client-side counterpart to the backend design round, and it is increasingly a distinct interview. You are asked to design something like an autocomplete, an infinite feed, a collaborative editor or a dashboard, and the graded material is component boundaries, the data-fetching and caching layer, how state is normalised, what happens offline or on a slow connection, and how the design degrades rather than breaks. It sits last because it draws on all eight of the topics above.
Where it sits in a real system
The frontend is the boundary where an internal data model becomes something a human can act on, and that translation is lossier than it looks. Your API returns entities; a user thinks in tasks. Almost every hard frontend problem lives in that gap.
Mechanically, you sit at the end of a delivery chain. HTML arrives, the browser parses it, discovers CSS and JavaScript, builds a DOM and a style tree, computes layout, paints, and composites. Blocking resources stall that pipeline. Then your JavaScript takes over and the second life of the page begins: fetching, caching, mutating, re-rendering.
flowchart TD
A[HTML bytes arrive and parsing begins] --> B[DOM tree built, subresources discovered]
B --> C[CSS parsed into a style tree]
C --> D[Style computed for every element]
D --> E[Layout assigns geometry]
E --> F[Paint produces layers]
F --> G[Composite puts layers on screen]The step to watch is C, because a stylesheet blocks the pipeline from reaching D at all — the browser will not paint content it might have to restyle. That is why a render- blocking stylesheet in the head delays first paint for every user, and why a synchronous script placed before it is worse still, since script execution can query layout and so must wait for style to be ready. Nearly every first-paint problem is one of those two things.
That gives you three architectural decisions that outrank every library choice. Where rendering happens — on the server per request, at build time, in the browser, or a mixture — which determines what a user sees before your code runs. Where state lives — server as source of truth with a client cache, or a client store you synchronise by hand. What crosses the network and when, because a beautifully structured client making eleven sequential requests is slower than an ugly one making two.
Those three decisions interact, which is what makes them architecture rather than configuration. Choosing server rendering changes where your state can live, because anything computed on the server has to be serialised and sent for the client to pick it up. Choosing a client cache as the source of truth changes what crosses the network, because the cache decides when a request is unnecessary. Getting the three to agree is most of what a frontend architect does, and a candidate who treats them as independent choices usually produces a design with a contradiction in it.
The frontend is also where security assumptions are most often misplaced. Anything you send to the browser is public, and any token you hold there is reachable by injected script. Client-side validation improves the experience; it never enforces a rule.
Choosing where rendering happens
Because the rendering decision outranks the framework decision, it deserves to be laid out plainly. The options are not competing fashions; each optimises a different thing and each has a cost you will feel later.
| Strategy | First paint contains | Best for | The cost you pay |
|---|---|---|---|
| Client rendered | An empty shell | Highly interactive apps behind a login | Slow first paint, weak crawlability |
| Server rendered per request | Full content | Personalised, frequently changing pages | Server cost and latency on every request |
| Statically generated at build | Full content | Content that changes rarely | Rebuilds to publish, stale until then |
| Static plus revalidation | Full content | Content that changes on a known cadence | Complexity, and a window of staleness |
| Streamed with partial hydration | Content progressively | Large pages with a slow section | Harder mental model, tooling dependence |
The row people choose by default is the first, and the reason it dominated for years is organisational rather than technical: a client-rendered application needs no server-side runtime for the interface, so one team can own everything. The cost lands on users with slow devices, because a shell that arrives quickly still shows nothing until a large JavaScript bundle has downloaded, parsed and executed.
The important thing to be able to say in an interview is that the choice is per route, not per application. A marketing page, a search results page and an authenticated dashboard in the same product have different requirements, and a mature answer assigns each of them a strategy and justifies it from what the page is for. Committing the whole application to one strategy because the framework's default suggested it is the answer that reads as junior.
Who does this work
Product frontend engineers build features: a day is reading a design, working out which existing components apply, discovering the API does not return what the screen needs, negotiating that, then handling the states designs habitually omit — empty, loading, partial, error, offline, too much data.
Design systems and UI engineers build the components everyone else consumes. The work is closer to library authorship: API design, accessibility correctness done once so that fifty consumers inherit it, and versioning changes that will break somebody.
Specialists exist where the stakes justify them. Performance engineers work from field measurement to specific regressions. Accessibility engineers audit against WCAG success criteria, test with actual assistive technology, and sit close to legal and procurement. Frontend architects decide rendering strategy, module boundaries and build tooling for many teams.
The distinction between building and consuming components is worth keeping in mind when you read a job advert, because it changes the interview. A product frontend role will test whether you can turn an ambiguous design into a working screen with all of its states handled. A design systems role will test API design, backwards compatibility and accessibility depth, and will care far more about the interface of your component than about the screen it appears on. Both call themselves frontend engineering, and preparing for one leaves you noticeably underprepared for the other.
Separately, a large population operates frontends without building them: analytics and experimentation teams, marketers deploying tags, content editors in a CMS. Their changes ship to your page and can undo your performance work, which is why tag governance is a frontend concern.
Demand, adoption and how that is changing
Demand is very high in aggregate, but it is not evenly distributed, and being honest about that matters more than the headline. Junior frontend is the most crowded entry point in software: it is the most tutorialised path, the barrier to producing something that looks finished is low, and screening now leans on browser-platform depth precisely to separate candidates that a portfolio cannot. Senior frontend is genuinely scarce. People who can own rendering strategy, untangle state in a large application, and hold accessibility and performance as engineering requirements are hard to hire, and companies feel it.
Three forces keep demand structural. Interfaces keep getting richer, so more of the product's complexity moved into the client and stayed there. Accessibility acquired legal weight rather than merely ethical weight — the European Accessibility Act's obligations took effect in June 2025, and public-sector accessibility rules already applied across the EU and the UK — so conformance is now a procurement gate, not a nice-to-have. And performance is tied to revenue closely enough that Core Web Vitals are tracked as a business metric.
The framework question deserves a straight answer. Churn is real but it is shallower than it feels: the durable knowledge is the platform underneath, and the platform has been stable and improving for years. Interviews have noticed. A senior frontend loop today is more likely to probe the event loop, rendering cost, caching, forms and semantics than the current idiomatic way to write a hook, because interviewers know framework idiom decays and platform knowledge does not.
There is one more shift worth naming, because it changes what a junior portfolio is worth. Generating a plausible-looking interface is now cheap, so a screenshot no longer distinguishes anyone. What distinguishes a candidate is the ability to say why the generated version is wrong — that the modal traps focus incorrectly, that the list re-renders on every keystroke, that the image has no dimensions and so shifts the layout. That is a critique skill, and it is built by measuring and auditing real pages rather than by building more of your own.
What makes it hard
The genuine difficulty is that you are writing concurrent, stateful software in an environment you cannot control, and every hard bug lives in the interaction rather than in one file.
The conceptual leap is derived state. Beginners store what they can see; the discipline is storing the minimum that cannot be computed, then deriving the rest. Once the same fact exists in two places they will disagree — the list says the item is deleted, the detail panel says it is not, and no single component is wrong. Server state makes this sharper because it is a cache of somebody else's data: it can go stale between paint and click, and every serious client eventually needs a story for invalidation, request deduplication and optimistic updates that can be rolled back.
What only bites in production is the environment. Your development machine is fast, near the server, and has a warm cache. The real user has a mid-range Android device, high latency, an extension injecting script, a translation layer rewriting the DOM, and text scaled to 200 per cent. Layouts that survive nothing else survive real content: names longer than the field, a currency that renders wider, a language that reads right to left.
Accessibility is where experience is least substitutable, because it is not a checklist you can reason through cold. You can pass automated checks and still ship something unusable — tooling catches a real but limited fraction of WCAG failures, and the rest is focus order, meaningful names, and whether a change gets announced. The reliable heuristic is that native semantic elements come with behaviour you would otherwise have to rebuild correctly, while ARIA changes what a browser reports without adding any behaviour at all.
// Two divs given a role. Nothing about them is actually a button, and
// role= does not add keyboard activation, focus, or disabled semantics.
<div role="button" onClick={submit}>Submit</div>
// The element that already is one: focusable, activated by Enter and Space,
// announced as a button, participates in the form, honours `disabled`.
<button type="submit">Submit</button>
The states nobody puts in the design
A design file shows one state: the successful one, with plausible content of a convenient length. Everything else is your problem, and the gap between a junior and a senior implementation of the same screen is mostly this list rather than anything architectural.
The empty state is the first screen a new user sees and is therefore the most important one in the product, which is precisely why it is usually an afterthought rendering as a blank panel. The loading state has to decide between a spinner, a skeleton and showing nothing, and the right answer depends on how long the wait usually is: a spinner that flashes for eighty milliseconds is worse than no indicator at all, which is why deliberate delays before showing one are common. The partial state arises when one of three requests has returned, and the choice is whether to render what you have or hold everything back until all of it arrives.
The error state is where most implementations are weakest, because a single generic message covers cases that need different responses. A validation failure is the user's to fix and belongs next to the field. A transient network failure is worth retrying and the interface should offer that. An authorisation failure means the user should not have been offered the action at all, which is a bug one layer up. A server error is nobody's fault and needs a way out that does not lose what they typed. Collapsing all four into "Something went wrong" is a decision, and usually the wrong one.
Then there are the states the environment imposes rather than the data. Offline, and whether your application detects it and queues rather than silently discarding. Stale, where the data on screen was true when it was fetched and is not now, which matters enormously on a page someone leaves open all day. Too much data, where the list the design showed with six rows has four thousand and every approach to rendering them has a cost. And content that does not fit, which is not really a state but behaves like one, because a name twice as long as the mock or a translated string half again as wide breaks layouts that were never tested against them.
Enumerating this list unprompted in a frontend design interview is a strong signal, because it demonstrates that you have shipped something rather than built something. The follow-up worth preparing is which of these states you would represent explicitly in your model — a single discriminated status rather than three independent booleans, so that loading-and-error cannot both be true and the impossible combinations simply cannot be constructed.
The single thread, precisely
Half the asynchronous bugs in frontend code, and a large share of the interview questions, come from an imprecise model of what "single-threaded" means. It does not mean one thing happens at a time in the browser; the browser does plenty in parallel. It means your JavaScript runs on one thread, and while it is running, nothing else on that thread can — including painting.
The loop has a definite shape. The engine takes one task from the task queue and runs it to completion. When it finishes, it drains the microtask queue entirely, and any microtask that queues another microtask is also drained in the same pass. Only then may the browser proceed to a rendering opportunity, where it runs animation-frame callbacks, recalculates style and layout, and paints. Then it takes the next task.
flowchart TD
A[Take one task from the task queue] --> B[Run it to completion]
B --> C[Drain the entire microtask queue]
C --> D{Time for a frame}
D -- no --> A
D -- yes --> E[Run animation frame callbacks]
E --> F[Recalculate style and layout]
F --> G[Paint and composite]
G --> AThe consequence to hold on to is the shape of the decision box. Rendering is not guaranteed after every task; it happens when the browser judges a frame is due, and it cannot happen at all while a task is running. So a single long task — an expensive computation, a synchronous loop over thousands of rows — blocks paint and blocks input handling for its whole duration, which is exactly what a poor Interaction to Next Paint score is measuring. Splitting that work into smaller tasks does not make it faster; it makes the page responsive while it happens, which is a different and usually more valuable thing.
The second consequence explains a classic interview question. A promise callback is a microtask and a timer callback is a task, so a resolved promise's continuation always runs before a timer scheduled with zero delay, even though the timer was registered first. That is not a quirk to memorise; it falls straight out of the loop above, and a candidate who derives it from the model rather than reciting the outcome is demonstrating the thing being tested.
A last consequence is that heavy work does not belong on this thread at all. A web worker runs on its own thread with no access to the DOM, which is a limitation and also the point: parsing a large response, running a search index or doing image work there leaves the main thread free to paint and to respond to input. Knowing when to reach for one, and being clear that it solves a responsiveness problem rather than a throughput problem, is the natural end of this line of questioning.
Why study it
Learn frontend if you want the shortest feedback loop in software — you change a line and see the consequence — and if the fact that a real person uses your output directly is motivating rather than incidental. It is also the best available education in event-driven, asynchronous programming, because the browser gives you no choice but to reason about it, and that transfers.
The senior case is stronger than the junior one. Frontend architecture, state design and performance work are scarce skills attached to visible business outcomes, and accessibility expertise is scarce enough to be a career on its own.
Be honest about who should not bother. If your goal is machine learning, data engineering or systems programming, this is a detour. If you want the highest-paid backend role in the least time, distributed systems and databases are a more direct route. And if what you enjoy is visual craft rather than programming, product design will suit you better than a frontend loop that spends an hour on the event loop.
If you are entering at the junior end anyway, the honest strategy is to be uncharacteristic. The crowded portfolio is a handful of applications built from tutorials; the uncrowded one is a documented performance improvement on a real site, an accessibility audit with the failures and the fixes, or a component whose keyboard behaviour you can defend in detail. Depth in the platform is both rarer and cheaper to acquire than breadth across frameworks, and it is what the screening round is now designed to find.
Your first hour
Take a page you did not build and measure it, because the habit of measuring rather than guessing is the whole of performance work.
Open a content-heavy public site in Chrome DevTools, and in the Network panel set throttling to a slow profile with the cache disabled. Reload and note what blocks the first paint. Switch to the Performance panel, enable CPU throttling, record a reload, and find the longest task. Then run Lighthouse and read only the Largest Contentful Paint and Cumulative Layout Shift entries with their attributions.
Now do the same to a page of your own and fix one thing — usually an unoptimised hero image, a blocking font, or a layout shift from an image without dimensions. Re-measure to confirm.
Spend the last twenty minutes on accessibility using the keyboard only. Unplug the mouse and tab through your page. Can you reach every control, see where focus is, open and close a dialogue, and submit the form? Most pages fail this within four presses. Write down each failure with the element that caused it.
Write the audit in the form below rather than as loose notes, because a defect with a cause and a fix attached is something you can talk about in an interview and a list of complaints is not.
Finding Focus is not visible on the primary navigation links
Cause A global outline reset with nothing replacing it
Impact A keyboard user cannot tell where they are, WCAG 2.4.7
Fix Restore a visible focus indicator with sufficient contrast
Verified Tabbed the full header again with the mouse unplugged
You finish with a before-and-after measurement of one real fix and a short keyboard-audit list, which is a more credible artefact than another tutorial application.
What this is not
It is not web design, and calling a frontend engineer a designer or the reverse annoys both. It is not "the easy half of full-stack" — the difficulty is differently shaped, not smaller, and the browser has more concurrency in it than most CRUD backends. It is not React, Next.js or any single framework, and framing your skills that way makes you look junior in exactly the round where you cannot afford to.
It is not a discipline where the visible output tells you the quality of the work, either. Two implementations of the same screen can be indistinguishable in a screenshot and differ by a second of load time, by whether a keyboard user can complete the task, and by whether the next requirement takes an afternoon or a fortnight. All three of those are invisible until someone measures, which is why measurement is treated here as a core skill rather than a specialism.
Nor is a component library accessibility. Adopting an accessible library removes a class of defects and leaves the ones that matter: your focus order, your form labelling, your error announcements, your custom widget that nobody tested with a screen reader.
It is not finished when it works on your machine, which sounds obvious and is the single most common cause of a defect reaching a user. The environment is the variable in this discipline, and a change that is not checked on a throttled connection, a small viewport and a keyboard has been checked in only one of the conditions it has to survive.
And it is not a field where framework knowledge compounds. What compounds is the platform: the layout algorithms, the event model, the caching rules, the semantics. Every hour spent there keeps paying after the current framework has been replaced, and that is the argument for spending your hours there deliberately rather than only when a bug forces you to.
Frameworks are how you write frontend this year; the browser is what you are writing for, and only one of those is still on the exam in five years.
Where to go next
Now practise it
14 interview questions in Frontend Engineering, each with the rubric the interviewer is scoring against.
- Angular, Vue and React are answers to the same problems. Compare how each handles change detection, reactivity and dependency injection.
- How do you decide between flexbox and grid, and why does z-index so often not do what you expect?
- Design the frontend for a data-heavy operational dashboard with live updates.
- A page has a poor Largest Contentful Paint. How do you diagnose it and what do you actually change?