cf.completefrontend
My progress
FUNDAMENTALS · MODULE 1

The RADIO framework

A five-part checklist, Requirements, Architecture, Data model, Interface, and Optimizations, for running a frontend system design interview: design the right thing, cover the basics fast, and save time for deep dives.

Why you need a framework at all

Picture two candidates who get the same prompt: "Design a news feed." Both know React well, and both have built infinite scroll at work.

One gets a strong hire, the other gets a no. The difference is not what they know but what they did with 45 minutes.

The first candidate starts drawing components in minute one. By minute 15 they have a nice FeedItem with likes and comments. Then the interviewer asks "what if the feed has 5,000 posts?", and they realise they never asked how big the feed is. They rewrite the list, run out of time, and never reach performance, accessibility, or errors.

The second candidate spends five minutes asking questions, sketches the big parts in about eight, names the data and the API in under ten more, and then says: "The two hard parts here are long-list performance and keeping the feed fresh. Let me go deep on those." They spend 15 minutes there, and that is where the interviewer learns the most about them.

Two timelines of the same 45-minute interview. Without a plan: 3 minutes of hellos, 15 minutes on FeedItem details, 10 minutes redoing the list after learning the feed holds 5,000 posts, 12 rushed minutes on data and API, then questions; performance, accessibility, and errors are never reached. With RADIO: hellos, requirements to minute 8, architecture to 16, data model to 20, interface to 25, then 15 minutes of deep dives until minute 40, then questions.no plan: drawing components from minute 1hiFeedItem detailsredo listrushed D + Iasknever reached: performance, accessibility, errorsRADIO: basics quickly, then deep diveshiRADIO: deep divesask15 minutes on the two hardest parts0816254045minutes into the interview
Same candidate knowledge, same prompt. The top run spends its time on rework; the bottom run covers the basics in 22 minutes and keeps 15 for the deep dives, where the level is decided.

What goes wrong without a plan

A system design prompt is short and vague on purpose. There is no single right answer, and nobody hands you a spec. That freedom is the trap. Without a plan, people fall into the same four holes again and again.

  • Designing the wrong thing. "Design an image carousel" can mean a hero banner with 5 slides or a product gallery with 200 zoomable photos. Skip the questions and you may solve a problem nobody asked about.
  • Spending the clock badly. Twenty minutes on a button component, then three rushed minutes on the parts that were actually hard.
  • Leaving holes. Forgetting the API, or never saying where data lives, so the interviewer has to drag it out of you, and that costs you points.
  • Freezing. A blank whiteboard and a silent interviewer make it hard to know what to say next. A plan always gives you a next step.

What RADIO stands for

RADIO is a name for the five things every frontend design answer needs to cover. Each letter is one part, and each part builds on the one before it. The mnemonic comes from Yangshun Tay's front end system design playbook on GreatFrontEnd, linked in the references.

LetterPartThe question it answers
RRequirementsWhat are we building, for whom, how well must it work, and what are we skipping?
AArchitectureWhat are the big parts on the client and server, and how does data flow between them?
DData modelWhat data does the client hold, what shape is it, and where does each piece live?
IInterfaceHow do the parts talk: the API calls to the server and the props and events between components?
OOptimizationsWhich two or three hard parts deserve a deep dive: performance, accessibility, offline, security?

The order is not random. You cannot draw the right parts until you know the requirements, and you cannot name the data until you know the parts that hold it.

You cannot design an API until you know the data it carries. And you cannot choose good optimizations until you know where the system is under strain.

A checklist, not a template

Here is the most important idea in this lesson. RADIO is a checklist for running the interview, not a form to fill in.

Strong answers do not sound like "Section R. Section A. Section D." They sound like a story of decisions: "Because the feed can hold thousands of posts, I'll virtualize the list, which means the data layer must give me items by index, so the API returns pages with a cursor." To virtualize a list means to render only the rows on screen.

That is why the problem guides on this site are written as a chain of decisions and not as five fixed boxes. Each chapter makes one choice, weighs the options, and shows how it shapes the next choice. RADIO is still there underneath: every guide starts with requirements, sketches the parts, names the data and the API, and spends its longest chapters on deep dives. You just don't see the labels.

Use RADIO the way a pilot uses a pre-flight checklist. The pilot does not read it aloud to the passengers, but they never take off without touching every item. In the interview, glance at the five letters every ten minutes and ask yourself: "Have I covered this yet? Is it the most useful thing to talk about now?"

Check your understanding · Exercise 1

Which of these are real benefits of following RADIO in an interview? Select all that apply.

How to spend 45 minutes

Time is the one resource you cannot get back in an interview, so plan it before you need it. The calendar invite may say 45 or 60 minutes, but you never get all of it for design. Introductions take a few minutes at the start, and many interviewers keep the last five minutes for your questions.

So a 45-minute slot gives you about 35 to 38 minutes of real design time. A 60-minute slot gives you about 50. Every minute you plan below comes out of that budget.

A default split

Start from this split for a 45-minute interview and bend it to the problem. The numbers are a starting point that has worked for many people, not a law. Notice that the last part gets the most time: that is on purpose.

MinutesPartWhat you should have at the end
0 to 3HelloNames, roles, and the prompt read out. Nothing to design yet.
3 to 8RequirementsA short list of functional and non-functional requirements, and what is out of scope, written where both of you can see it.
8 to 16ArchitectureA box diagram: the main client parts, the server or API, and arrows for how data flows.
16 to 20Data modelThe main entities with their key fields, and where each kind of state lives.
20 to 25InterfaceOne or two API calls with their shape, and the props or events of the main component.
25 to 40OptimizationsTwo or three deep dives, each with the problem, your solution, and its cost.
40 to 45Your questionsTime for you to ask about the team. Wrap up the design in one sentence before this.
A timeline of a 45-minute interview. Hello from 0 to 3 minutes, requirements 3 to 8, architecture 8 to 16, data model 16 to 20, interface 20 to 25, optimizations 25 to 40, the longest phase, and your questions 40 to 45. Three checkpoints are marked: requirements written by minute 8, a box diagram drawn by minute 16, deep dives started by minute 25.requirements writtenbox diagram drawndeep dives starthihelloRRequirementsAArchitectureDDataIInterfaceOOptimizations?questions0381620254045minutes into a 45-minute interview
About 37 of the 45 minutes are design time. The three checkpoints are what you watch instead of a stopwatch: miss one by more than a few minutes and cut something, out loud.

Why the last part gets the most time

Requirements, architecture, data, and interface are the parts most candidates get roughly right. They are necessary, but they rarely separate a mid-level engineer from a senior one. The deep dives are where you show real depth: why the list needs virtualization at 2,000 items, how you stop an old search response from overwriting a newer one, how focus moves in a modal.

So the goal of the first four parts is to be correct and quick. Cover them well enough that the deep dives rest on solid ground, then move on. If you are still on the data model at minute 30, the interviewer will have little to score you on in the area that matters most.

Bending the split to the question

Different questions put the weight in different places. A component question, like an autocomplete or a date picker, has a tiny server side and a rich component API, so Architecture shrinks and Interface grows. An app question, like a news feed or a chat app, has more moving parts, so Architecture and Data model grow. Try it in the planner below: the feature setting reproduces the table above, and the other two show how the split bends.

Length:
Question:
Requirements ran over by:
A 45-minute feature question: 3 minutes of hellos, 37 minutes of design split as Requirements 5 min, Architecture 8 min, Data model 4 min, Interface 5 min, Optimizations 15 min, then 5 minutes for your questions.hi3R5A8D4I5O15?50 min45 min
Each box is one part, drawn to scale. The green box is the deep dives. When requirements run long, the extra minutes come out of the interface, data model, and architecture first, so the deep dives keep their time.

Design time: 37 of 45 minutes. Requirements 5 min, Architecture 8 min, Data model 4 min, Interface 5 min, Optimizations 15 min.

A feature question sits between the two: a few parts inside a bigger product, with both a server API and a component API to sketch.

Checkpoints, not a stopwatch

You can't stare at a clock while you think, so use two or three checkpoints instead. A simple set for 45 minutes: requirements written down by minute 8, a box diagram by minute 16, and deep dives started by minute 25. If you miss a checkpoint by more than a few minutes, cut something, out loud.

Saying it out loud matters. "We're at 22 minutes and I haven't touched performance, so I'll keep the API short: one paginated endpoint, and I can expand it later if you want" sounds like someone who is in control. Quietly running over sounds like someone who is lost.

Check your understanding · Exercise 2

It is minute 24 of a 45-minute interview for "Design a chat app". You have requirements and a box diagram, but no data model or API yet. What is the best move? Select all that apply.

R: Requirements

Requirements turn a one-line prompt into something you can design. You get them by asking questions, even when the prompt seems clear. The answers decide almost everything that follows, so this is the cheapest place to avoid a wrong turn.

Sort what you learn into three lists and write them where the interviewer can see them. Written requirements become your contract: later, when you choose between two designs, you point back at them.

Functional requirements: what it does

Functional requirements are the things a user can do. Write them as short user actions, three to six of them, most important first. For a news feed: "see a list of posts from people I follow", "scroll to load older posts", "like a post", "create a text post with an image".

Keep the list short on purpose. Each item becomes a part of your design, so ten items means ten parts and no time for depth. If the interviewer lists many features, ask which three matter most and put the rest under out of scope.

Non-functional requirements: how well it works

Non-functional requirements describe quality: speed, scale, devices, accessibility, reliability. They are where frontend interviews are won, because they decide the deep dives. Give each one a number whenever you can. "Fast" means nothing; "first posts visible in under 2.5 seconds on a mid-range phone on 4G" is something you can design for.

QualityVagueWith a number
Load speedIt should load fast.Largest Contentful Paint (LCP, when the main content appears) of 2.5 s or less for 75% of visits.
ResponsivenessTyping shouldn't lag.Interaction to Next Paint (INP, the delay after a tap or key press) of 200 ms or less.
Visual stabilityNo jumping.Cumulative Layout Shift (CLS, how much the page jumps) of 0.1 or less, so images and ads reserve their space.
Scale of dataLots of posts.Up to 5,000 items in one list; 20 per page; images up to 2 MB before resizing.
FreshnessReal time.New messages appear within 1 second; feed updates within 30 seconds are fine.
SizeLightweight.The widget adds under 30 KB of gzipped JavaScript to the page.
AccessibilityAccessible.Meets WCAG 2.2 AA (the Web Content Accessibility Guidelines, level AA): full keyboard use, screen reader labels, 4.5 to 1 text contrast.

You do not need the interviewer to give you the numbers. If they say "you decide", propose them yourself: "I'll aim for the Core Web Vitals good thresholds: LCP within 2.5 seconds, INP within 200 ms, CLS at most 0.1." Proposing a sensible number shows you know what good looks like.

The questions that change the design most

Some questions matter far more than others, because one answer changes the whole design. Ask those first. A good test: if both possible answers lead to the same design, the question can wait.

QuestionIf the answer is smallIf the answer is big
How many items can the list hold?Up to 100: render them all.Thousands: paginate, and virtualize the list (render only what is on screen).
Which devices?Desktop only: hover, big screens, fast CPU.Mobile web too: touch, small screens, slow CPU, flaky network, smaller bundles.
How fresh must data be?Minutes: fetch on load, refresh on focus.Under a second: a push channel such as WebSockets or server-sent events.
Must it work offline?No: show an error and a retry button.Yes: a service worker, a local store such as IndexedDB, and a queue of unsent writes.
Who can see it?Logged-in users only: render on the client.Public and found by search engines: render HTML on the server.
How many languages?One: plain strings.Many, including right-to-left: message catalogs, logical CSS properties, locale-aware dates and numbers.
A decision tree from one question, how many items can the list hold. Under 100: render them all, with a plain array, one GET request, and nothing hard to optimize. Hundreds: paginate, with pages of data, a cursor in the API, and focus handling for a Load more button. Thousands or endless: virtualize, with items by index, cursor paging, and deep dives on the virtual list and row heights.How many items?under 100hundredsthousands, endlessRender allD: plain arrayI: one GETO: nothing hardPaginateD: pagesI: ?cursor=O: Load more focusVirtualizeD: items by indexI: ?cursor=O: virtual list,row heights
One answer changes the data model (D), the interface (I), and the deep dives (O) at once. That is why you ask this kind of question first, and why a question whose answers lead to the same design can wait.

Out of scope: say what you will skip

The third list is just as useful. Out of scope is what you and the interviewer agree not to design today: login, the admin panel, payments, server databases. Saying it protects your time and shows you know those parts exist. Without it, a vague prompt grows until it eats the interview.

Decision The interviewer answers "what do you think?" to your questions. How do you settle the requirements?

Keep asking

Rephrase the question and ask again until they pick an answer.

Pros

  • You never design on a wrong guess.

Cons

  • Burns minutes.
  • Looks like you can't make product decisions on your own.

Assume and say it

Pick a sensible answer, say it out loud with the reason, write it down, and move on: "I'll assume up to 5,000 posts, since that's a heavy user's feed."

Pros

  • Fast.
  • Shows product sense.
  • The interviewer can correct you in one sentence.

Cons

  • If you pick something odd and they don't stop you, the design drifts.

Offer a fork

Name both answers and how each would change the design, then pick one: "If it's tens of items I'd render them all; if it's thousands I'd virtualize. I'll design for thousands."

Pros

  • Shows you see how requirements drive design.
  • Gives the interviewer a clear choice.

Cons

  • Takes a little longer than a plain assumption; save it for questions with a big impact.

What we pick: Assume and say it for most questions, and offer a fork for the one or two questions that change the design the most. Both keep you moving and show judgement, which is what this part is scored on.

Check your understanding · Exercise 3

For "Design a photo gallery", which of these are non-functional requirements? Select all that apply.

A: Architecture

Architecture is the big picture: the main parts of the system, what each one is responsible for, and how data moves between them. In a frontend interview it is a drawing of boxes and arrows, and it should fit on half a whiteboard. If it needs the whole board, the boxes are too small.

The boxes most frontend designs share

Most frontend designs, from a widget to a whole app, use the same handful of boxes. Learn them as a starting kit, then rename and add to them for each problem.

  • Server or API. Where the data comes from. One box is usually enough. Add a CDN (content delivery network, servers near the user that serve static files and cached responses) if images or scripts matter.
  • Data layer or API client. The only part that talks to the network. It builds requests, handles retries and errors, and turns responses into the client's data shape.
  • Store or cache. Where the client keeps data it has fetched, so two views showing the same post share one copy. In code this may be a library like TanStack Query, Redux, or a simple context.
  • Controller or container. The glue for one feature: it reads from the store, tells the data layer what to fetch, and passes plain data down to the views.
  • Views. The components the user sees. Given data and callbacks, they render. They do not fetch.
Two zones. In the browser, four boxes stacked: views that render and never fetch, a controller per feature, a data layer that holds the only network code, and a store that keeps posts by ID. A user event goes from the views to the controller, the controller asks the data layer to fetch with a cursor, the data layer saves results by ID into the store, and a curved arrow carries new data from the store back up to the views. On the server side: a CDN sends assets to the views, an API or BFF answers the data layer over HTTP, and a push channel such as a WebSocket or server-sent events feeds the store.BrowserServer sideViewsrender, never fetchControllerone per featureData layerthe only network codeStoreposts by IDuser eventfetch(cursor)save by IDCDNHTML, JS, imagesAPI or BFFJSON over HTTPPush channelWebSocket or SSEassetsHTTPpush
Data goes round one way: user events travel from the views through the controller and data layer into the store, and new data returns to the views along the curved arrow on the left. Pushed updates enter at the store, like fetched ones, so the views never care where data came from.

For each box, say its job in one sentence as you draw it. "The feed store holds posts by ID and the order of IDs for the feed." If you need "and" three times, the box does too much: split it. If two boxes have the same job, merge them.

Client versus server: where does each part run?

A frontend design is mostly about the client, but it must say where the line with the server sits. Two decisions draw that line. First, where the HTML is rendered: on the server for fast first paint and search engines, or in the browser for rich, app-like screens. Second, where the logic sits: filtering 50 items can happen in the browser; ranking a feed of a million posts belongs on the server.

You can also add a thin server that belongs to the frontend team, often called a backend for frontend (BFF). It calls several backend services and returns exactly what one screen needs in one response. Mention it when a screen would otherwise need five requests to draw.

Data flow: draw the arrows with a direction

Arrows matter as much as boxes. Draw them with a direction and say what travels on them. A good default for the client is one-way flow: user events go up from views to the controller, the controller asks the data layer, the data layer updates the store, and the store's new data flows down into the views.

Then add the second kind of flow if the problem has it: data the server pushes without being asked, such as new chat messages over a WebSocket. Draw it as its own arrow into the store, because it arrives at any time and must merge with what is already there.

Think first

A candidate draws one big box called "App" with an arrow to "Server". What is missing, and what would you add?

D: Data model

The data model is the list of things the client knows about, their important fields, and where each piece of state lives. It is short, but it is the step people skip most, and skipping it makes the API and the deep dives vague.

Entities: the nouns of the problem

An entity is a kind of thing with an identity, like a Post, a User, or a Message. Find them by reading your functional requirements and underlining the nouns. Most frontend questions have two to five.

For each entity, list only the fields that drive a decision. A Post has dozens of fields in real life; in the interview, id, author, createdAt, body, imageUrl, and likeCount are enough, because they decide sorting, rendering, image loading, and the like button.

ts
type User = { id: string; name: string; avatarUrl: string };

type Post = {
  id: string;
  authorId: string;      // points to a User, not a copy of it
  createdAt: string;     // ISO date, used for order and "2h ago"
  body: string;          // user text: render as text, never as HTML
  image?: { url: string; width: number; height: number };
  likeCount: number;
  likedByMe: boolean;    // drives the button state
};

type FeedState = {
  postIds: string[];     // the order, from the server
  nextCursor: string | null;
  status: "idle" | "loading" | "error";
};
Image width and height let the page reserve space before the image loads, which keeps CLS low. likedByMe is what an optimistic like (one shown before the server confirms it) flips.
On the left, a graph of three entities. A Post points to its User through authorId, a Comment points to its Post through postId and to its User through authorId. On the right, the client store, normalized: feed.postIds holds the order p3, p2, p1; posts by ID holds p1, p2, and p3 once each, with p2 highlighted; users by ID holds u7 and u9. A like on p2 changes one cell.UserPostCommentauthorIdpostIdauthorIdclient store, normalizedfeed.postIdsp3p2p1posts by IDp1p2p3users by IDu7u9like p2: one cell changes
Entities point to each other by ID instead of holding copies. The store keeps each one once, and lists such as feed.postIds hold only IDs, so a change to one post shows everywhere that post appears.

Where each piece of state lives

This is the part that shows real frontend thinking. The same value behaves very differently depending on where you keep it. There are five common homes, and choosing well removes whole classes of bugs.

HomeGood forLives untilExample
ServerThe source of truth for shared data.Forever, for every device.Posts, likes, messages.
Client cache or storeA copy of server data, shared by all views.The tab closes or the data goes stale.The feed's posts by ID.
URLState a user should be able to share, bookmark, or get back with the Back button.The user navigates away.Search query, filters, current tab, page.
Browser storageState that should survive a reload or going offline.Cleared by the user or the browser.A draft post in localStorage, offline messages in IndexedDB.
ComponentShort-lived UI state only one component cares about.The component unmounts.Is the menu open, the text being typed, hover.

Two rules cover most cases. First, keep server state (copies of server data) apart from UI state (what the user is doing right now). They change for different reasons and need different tools.

Second, store shared entities once, by ID, and let lists hold IDs. A store kept this way is called normalized. Then a like on a post updates the feed, the post page, and the profile at the same time, because there is only one copy.

Check your understanding · Exercise 4

In a chat app, which pairings of state and home are good choices? Select all that apply.

I: Interface

The interface is how the parts talk to each other. In a frontend design there are two kinds. The server API is the contract between the client and the server: requests and responses. The component API is the contract between a component and the code that uses it: props in, events out.

App questions lean on the server API. Component questions, like "design a date picker", lean almost entirely on the component API, because the component may never call a server itself. Know which one your question needs and spend your minutes there.

The server API: one or two calls, done well

You do not need every endpoint. Pick the one or two calls that the hard parts depend on and give each one four things: the method and path, what it sends, what it returns, and how it fails. Name the fields that drive a decision, like the cursor for paging or the version number for conflict checks.

http
GET /api/feed?cursor=p_9f2c&limit=20

200 OK
{
  "posts": [ { "id": "p_9f1a", "authorId": "u_7", ... } ],
  "users": { "u_7": { "name": "Asha", "avatarUrl": "..." } },
  "nextCursor": "p_9e77"   // null when there are no older posts
}

POST /api/posts/p_9f1a/like      -> 204 No Content
DELETE /api/posts/p_9f1a/like    -> 204 No Content
A cursor (an opaque pointer to the last item seen) stays correct when new posts arrive at the top, unlike page numbers. Sending users once in a map matches the store, which keeps one copy of each user.

Say why you chose the shape. "Cursor and not page number, because new posts are added at the top while the user scrolls, and page 2 would then repeat posts from page 1." One reason like this is worth more than five extra endpoints.

A sequence diagram across the view, the store, the data layer, and the server. The user taps like in the view. The store answers at once with liked and a count of 42, an optimistic update. The store asks the data layer to likePost p1. The data layer sends POST /p1/like to the server. The server replies 500. The data layer reports failed to the store. The store tells the view to undo, back to 41.ViewStoreData layerServertap likeliked, 42likePost(p1)POST /p1/like500failedundo, 41
Each arrow is part of an interface: props and events between view and store, a function between store and data layer, HTTP between data layer and server. Saying how a call fails, and what the client does then, is the part most answers leave out.

Decision Which protocol should the client use to talk to the server?

REST over HTTP

One URL per resource, standard methods (GET, POST, PATCH, DELETE), JSON bodies.

Pros

  • Simple and familiar.
  • Works with standard HTTP caching and CDNs.
  • Easy to debug in the Network panel.

Cons

  • A screen that needs data from many resources may need several requests, or a custom endpoint.

GraphQL

One endpoint; the client sends a query naming exactly the fields it needs, often across several types.

Pros

  • One request per screen, no extra fields.
  • Typed schema shared by teams.

Cons

  • Harder to cache at the HTTP level, since most queries are POSTs to one URL.
  • A client library and a schema to maintain.

A push channel (WebSocket or server-sent events)

A long-lived connection the server can send on at any time: WebSockets both ways, server-sent events (SSE) server to client only.

Pros

  • Updates arrive in well under a second.
  • No wasted polling requests.

Cons

  • Connections to keep alive, reconnect, and scale.
  • Usually added next to REST, not instead of it.

What we pick: Default to REST for reads and writes, and say so in one sentence. Mention GraphQL when one screen pulls from many sources. Add a push channel only when a requirement needs updates within seconds, like chat or live scores, and keep REST for everything else.

The component API: props in, events out

For a component, the interface is its props. Group them into three kinds: the data it shows, the events it reports, and the options that change how it looks or behaves. Then decide one key question: is it controlled (the parent owns the value and passes it in) or uncontrolled (the component keeps the value itself)? Good library components support both.

tsx
type AutocompleteProps<T> = {
  // data
  fetchSuggestions: (query: string, signal: AbortSignal) => Promise<T[]>;
  getLabel: (item: T) => string;
  // controlled or uncontrolled value
  value?: T | null;
  defaultValue?: T | null;
  // events
  onSelect: (item: T) => void;
  onQueryChange?: (query: string) => void;
  // options
  minChars?: number;     // default 2
  debounceMs?: number;   // default 200
  renderItem?: (item: T, active: boolean) => React.ReactNode;
  label: string;         // required, for screen readers
};
The AbortSignal lets the component cancel an old request when the user keeps typing. Making label required is an accessibility decision written into the API.

Check your understanding · Exercise 5

Which of these are strong things to say while defining the interface for an infinite news feed? Select all that apply.

O: Optimizations and deep dives

Optimizations are where the interview is decided. By now you have a design that works. This part shows whether you can make it work well: fast on a cheap phone, usable with a keyboard and a screen reader, safe, and calm when the network fails.

The trap is to list everything you know: "lazy loading, code splitting, memoization, CDN, compression, service workers...". A list like that takes a minute and earns almost nothing, because it shows you have heard of things, not that you can use them. Instead, pick two or three areas and go deep.

The areas to choose from

AreaWhat it coversA deep question in it
Network performanceWhat loads first, caching, prefetching, payload size, request count.How do you show the first 10 posts in under 2.5 s on 4G?
Rendering performanceLong lists, re-renders, layout work, main-thread time.How do you scroll 5,000 rows at 60 frames per second?
AccessibilityKeyboard use, focus, roles and labels, live announcements, contrast, reduced motion.How does a screen reader user know 3 new suggestions appeared?
InternationalizationTranslated strings, plural rules, dates and numbers, right-to-left layout, long words.What breaks when the UI is shown in Arabic or German?
SecurityCross-site scripting (XSS), user HTML, tokens, cross-site request forgery (CSRF), third-party scripts.A post body can contain <script>: how do you render it safely?
Offline and reliabilityErrors, retries, timeouts, offline queues, conflict handling.The user likes 3 posts in a tunnel: what happens when they're back online?
User experience statesLoading, empty, error, partial, and stale states, not just the happy path.What does the user see while page 2 loads, and if it fails?

How to pick the two or three

Pick the areas where this problem is under the most strain. Three questions find them quickly, and each one points back at earlier RADIO steps. That is why the earlier steps matter: they tell you where to dig.

  1. Which non-functional requirement is hardest to meet? "5,000 items" points at rendering. "Messages within 1 second" points at the push channel and reconnects. "Works offline" points at storage and sync.
  2. What is special about this problem? Every app needs loading states. Only an autocomplete has out-of-order responses on every keystroke; only an editor has two people typing in the same place. The special part is the most interesting deep dive.
  3. What is the interviewer hinting at? If they asked twice about mobile, or said "lots of users", they are telling you what they want to score. Follow the hint.
A matrix of six questions against six areas: network, rendering, accessibility, internationalization, security, and offline. Autocomplete: deep dives on network and a11y; News feed: deep dives on network and render; Chat app: deep dives on network and render and offline; Collab editor: deep dives on network and offline; Image carousel: deep dives on network and a11y; Date picker: deep dives on a11y and i18n. Most other cells deserve one sentence, and some none.networkrendera11yi18nsecurityofflineAutocompleteNews feedChat appCollab editorImage carouselDate pickerdeepdeepsaysaydeepdeepsaysaysaydeepdeepsaysaysaydeepdeepsaysaysaydeepdeepsaydeepsaydeepdeepdeep: a deep dive · say: one sentence · blank: skip
Where each question is usually under strain. Every row has only two or three deep dives; the rest get a sentence or nothing. Your requirements can move a cell, which the picker below lets you try.

The shape of a good deep dive

A deep dive is a small story, and it has the same five beats every time. Practise them until they are automatic. With two or three deep dives in about 15 minutes, each beat gets about a minute.

  1. The problem, with a number. "Rendering 5,000 post cards creates about 200,000 DOM nodes, and scrolling janks on a mid-range phone."
  2. The options. "Paginate with a Load more button, use content-visibility: auto, or virtualize the list."
  3. Your choice and why. "Virtualize, because the feed is endless and we need steady memory."
  4. How it works, briefly. "Render only the rows in view plus a few above and below, measure each row once, and keep scroll position when new posts load."
  5. The cost and how you'd check it. "Find-in-page and screen readers can't see unrendered rows, so I'd keep aria-setsize and aria-posinset on each row. I'd check with a performance trace on a throttled phone."
Question:
Requirements and hints:
How much strain each area is under for News feed: Network 4, Rendering 4, UX states 3, Accessibility 2, Security 2, i18n 1, Offline 1. The top three are Network, Rendering, UX states.Network4Rendering4UX states3Accessibility2Security2i18n1Offline1
Bars show how much each area is under strain, highest first. The three green bars are your deep dives; the rest get a sentence at most.

Deep dives for News feed:

  1. Network. Images and pages: what loads first, image sizes, cursor paging.
  2. Rendering. A long list: virtualize, and keep the scroll position steady as posts load.
  3. UX states. Loading, empty, error, and "new posts" states at the top.

Check your understanding · Exercise 6

For "Design a search autocomplete", which would make the strongest deep dives? Select all that apply.

Adapting RADIO to component and app questions

Frontend design questions come in roughly three sizes, and RADIO bends to each. A component question asks for one reusable piece of UI: an autocomplete, a modal, a date picker, an image carousel. An app question asks for a whole product: a news feed, a chat app, an email client. A feature question sits in between: a comment section, a notification bell, a checkout form inside a bigger site.

The five letters stay the same. What changes is how much time each one gets and what you draw for it. Spot the size in the first minute, because it tells you where to spend the next 40.

LetterComponent questionApp question
RequirementsWho uses it (other developers and end users), which interactions, how many items, which browsers, how much it may add to the bundle.Core user flows, scale of data and users, devices, freshness, offline, search engines.
ArchitectureSmall: the component's inner parts (input, list, popup), and maybe a data source. Often 3 or 4 boxes.Large: pages, routing, rendering strategy, store, data layer, server, CDN, push channel.
Data modelInternal state: open or closed, active index, value, query, loading.Entities and their relations, the normalized store, URL state, offline storage.
InterfaceThe main event: props, events, controlled versus uncontrolled, render slots, theming.Mostly server API: endpoints, pagination, errors, real-time messages.
OptimizationsAccessibility, keyboard, focus, rendering many items, bundle size, browser quirks.Load speed, caching, long lists, real time, offline, security, i18n.

Component questions: think like a library author

For a component, your user is two people: the developer who drops it into their app, and the person who clicks it. The developer cares about the props, how to style it, how big it is, and whether it works with their state. The end user cares about keyboard support, screen readers, touch, and speed.

So the Interface step becomes the centre of the design, and accessibility is almost always one of your deep dives. A good check: could another team use your component without reading its source? If the answer needs "well, you'd have to...", the API needs work.

App questions: think like a tech lead

For an app, the challenge is breadth. There are more parts, more data, and more ways to fail, and you will not cover them all. Requirements must cut scope hard, Architecture must show the whole system in one picture, and the deep dives pick the two or three places the app is under strain.

App questions also bring up decisions that component questions never do: how pages are rendered (server or client), how routes are split into bundles, how the store is shaped across features, and how the client gets updates. You do not need to deep dive all of them, but you should name your choice for each in a sentence.

Check your understanding · Exercise 7

You are asked to "Design a modal dialog component for our design system". Where should most of your time go? Select all that apply.

Driving the conversation, and the mistakes that sink people

An interviewer can only score what they hear and see. A great idea you keep in your head counts for nothing. So the skill here is not only designing, but designing out loud in a way that is easy to follow and easy to steer.

Good candidates drive. They say where they are going, check in at the end of each part, and invite the interviewer to redirect them. The interviewer becomes a teammate in a design review, not an examiner waiting for mistakes.

The loop: propose, explain, check in

Each RADIO part runs through the same small loop. You propose something concrete, explain the reason and the main trade-off, then check in. If the interviewer agrees, you move on; if they push back or hint, you adjust and loop again. The check-in is one sentence, not a request for permission.

A state machine for one RADIO part. Start at Propose, a concrete choice. Go to Explain, the reason and the cost. Go to Check in, one sentence. If the interviewer agrees, go to Next part and tick the letter. If they give a hint or push back, go to Adjust, take the hint, and return to Propose with a new choice.startProposea concrete choiceExplainreason and costCheck inone sentenceAdjusttake the hintNext parttick the letteragreedhint or pushbacknew choice
Every part, from requirements to deep dives, runs this loop. The check-in is one sentence, not a request for permission; a hint sends you round the loop again with a better choice.

Phrases that do real work

MomentWhat to say
Start"Before I design anything, I'd like to ask a few questions to pin down scope. Then I'll sketch the parts, the data, and the API, and spend most of the time on the hardest parts."
Moving on"That covers requirements. Moving to the architecture."
Making a choice"I could do A or B. A is simpler; B handles the 5,000-item case. Given our requirements, I'll go with B."
Unsure"I'm not certain of the exact browser support for that; I'd check MDN, and if it's missing I'd fall back to X."
Time check"We're at about 25 minutes. I'd like to spend the rest on two deep dives: list performance and offline likes."
Check-in"Does that level of detail work, or would you like me to go deeper here?"
Wrap-up"To sum up: a virtualized feed with a normalized store, cursor paging, and optimistic likes. Next I'd look at image loading."

Taking hints

Interviewers drop hints when they want you somewhere else. "Interesting, and what if the user is on a train?" means "talk about offline and flaky networks". "How would that feel with 10,000 rows?" means "talk about rendering performance". Treat each question as a direction, not a test of your first answer.

When a hint shows your design has a hole, say so plainly and fix it: "Good point, my current design would re-render every row on each like. Let me change the store so each row subscribes only to its own post." Changing your mind with a reason is a strong signal. Defending a weak choice is a weak one.

Mistakes that sink good candidates

  • Designing before asking. Answering the wrong question well scores worse than answering the right question roughly.
  • Going silent. Long pauses leave the interviewer with nothing to score. Think out loud: "I'm weighing pagination against virtualization..."
  • Using RADIO as a script. Reading out headings and filling each one equally sounds rehearsed and wastes time on easy parts.
  • Listing instead of choosing. Naming ten techniques is not a design. Pick one, say why, and name its cost.
  • Designing the backend. Twenty minutes on database sharding in a frontend interview is twenty minutes not spent on what they came to score.
  • Only the happy path. No loading, empty, error, or offline states. Real products spend much of their code on these.
  • Buzzwords you can't defend. If you say "islands architecture" or "CRDT", expect a follow-up. Only use terms you can explain in two sentences.
  • Ignoring the clock. Reaching deep dives at minute 38 leaves no room for the part that decides the level.

Think first

Halfway through, the interviewer says "What happens if two tabs are open?" You hadn't thought about it. What do you do?

A worked example: "Design a search autocomplete"

Let's run the whole framework on one small question, with the minute marks, so you can see how the parts connect and how little time the basics need. The prompt: "Design the search box with suggestions for our online bookshop." The step-through below follows the same run.

The autocomplete answer, minute by minuteStep 1 of 7: Read the prompt, minutes 0 to 3

Five boxes for R, A, D, I, and O across the top, filling in as the answer moves through them, and a sticky note below with what is written on the board at each step.RADIOminutes 0 to 3R A D I Oplan: ask, sketch, thengo deep on the hard parts
"Design the search box with suggestions for our bookshop." Write R A D I O down the side of the board and say the plan in one sentence.

Read the prompt, minutes 0 to 3: "Design the search box with suggestions for our bookshop." Write R A D I O down the side of the board and say the plan in one sentence.

Minutes 3 to 7: requirements

The candidate asks five questions and writes down the answers. It is a feature in the shop that should be reusable later, and it suggests book titles and authors, up to 8.

Half the traffic is mobile. Speed is left to the candidate ("you decide"), and the interviewer asks them to assume the site must meet WCAG AA.

  • Functional: show up to 8 suggestions as the user types; pick one with mouse, touch, or keyboard; pressing Enter with no pick runs a full search.
  • Non-functional: suggestions within 400 ms after typing stops on 4G; no flicker or wrong results; full keyboard and screen reader support; under 10 KB of gzipped JavaScript.
  • Out of scope: the search results page, the ranking algorithm on the server, spelling correction.

Minutes 7 to 12: architecture

Four boxes. The input reports what the user types. A controller debounces typing (waits until typing pauses), checks a small cache, and calls the suggest API through a data layer. A listbox popup shows the results.

Data flows one way: keystrokes go up to the controller, suggestions come down to the popup. The server is one box labelled "suggest API, behind a CDN".

A wireframe of the bookshop search box. The input holds harr and has role combobox with aria-expanded true. Below it a popup lists four suggestions: Harry Potter (book), Harriet Evans (author), which is highlighted as the active option, Harrow the Ninth, and Harry Hole (series). Notes say the active option is set with aria-activedescendant, and a polite live region says 4 suggestions.bookshop.exampleSearch booksharrHarry Potter (book)Harriet Evans (author)Harrow the NinthHarry Hole (series)role=comboboxaria-expanded=trueactive option viaaria-activedescendantlive region says"4 suggestions"
The four boxes from the architecture step on screen: input, popup, and the controller and API behind them. Focus stays in the input while arrow keys move aria-activedescendant, so typing never stops.

Minutes 12 to 20: data model and interface

The state is small: query, items, activeIndex (which suggestion is highlighted, or -1), isOpen, and status (idle, loading, error). A cache maps each query to its items, keeps the last 50, and drops the oldest first. The query does not go in the URL; the results page will put it there.

http
GET /api/suggest?q=harr&limit=8

200 OK
Cache-Control: public, max-age=300

{ "query": "harr",
  "items": [ { "id": "b_101", "label": "Harry Potter and the...", "kind": "book" },
             { "id": "a_42",  "label": "Harriet Evans", "kind": "author" } ] }
Echoing the query back lets the client check that a response matches what is in the box. The Cache-Control response header lets the browser and the CDN reuse an answer for five minutes, so popular prefixes never reach the server.

The component API takes fetchSuggestions, onSelect, label, and an optional renderItem, as in the interface chapter. The candidate says one sentence on why fetchSuggestions receives an AbortSignal: so old requests can be cancelled.

Minutes 20 to 40: three deep dives

The candidate proposes three deep dives, and the interviewer agrees. Each follows the five beats from the optimizations chapter: problem, options, choice, how it works, cost.

  1. Request count. Typing "harry potter" is 12 keystrokes, which could be 12 requests. A 200 ms debounce plus a 2-character minimum and the cache usually cut it to 2 or 3. Cost: 200 ms of added delay, which leaves about 200 ms for a request served from the CDN and still fits the 400 ms target.
  2. Out-of-order responses. The response for "har" can arrive after the one for "harr" and overwrite it. Fix: abort the old request with AbortController, and also drop any response whose query does not match the current input. Cost: almost none.
  3. Accessibility. Use the combobox pattern from the WAI-ARIA Authoring Practices (the W3C guide to accessible widgets): the input has role="combobox", aria-autocomplete="list", aria-expanded, and aria-controls pointing at a role="listbox" of role="option" items; arrow keys update aria-activedescendant to the highlighted option, so focus stays in the input; Escape closes; a polite live region says "8 suggestions". Cost: careful testing with a screen reader such as VoiceOver or NVDA.

Just before minute 40, the candidate names what they would do next: highlight the matched letters using text nodes, never innerHTML, so a book title cannot inject script; and keep the popup inside the viewport on small screens. Then they sum up in one sentence. Notice that no step was skipped, yet the basics took 17 minutes and the deep dives took 20.

Check your understanding · Exercise 8

In the worked example, which choices trace straight back to a written requirement? Select all that apply.

Summary

  • RADIO stands for Requirements, Architecture, Data model, Interface, and Optimizations. Each part builds on the one before.
  • It is a checklist for running the interview, not a template to read out. Strong answers sound like a story of decisions with RADIO underneath.
  • In 45 minutes you get about 37 minutes of design. Cover the first four parts correctly and quickly, and save about 15 minutes for deep dives (about 20 in a 60-minute slot).
  • Write requirements in three lists: functional, non-functional with real numbers, and out of scope. Ask first the questions whose answer changes the design.
  • Draw a few boxes with one job each and arrows with a direction. Name the entities, store shared data once by ID, and put each piece of state in the right home: server, store, URL, browser storage, or component.
  • Define one or two API calls well, with why and how they fail. For components, the props and events are the design.
  • Pick two or three deep dives where the problem is under strain, and run each as problem, options, choice, how it works, and cost.
  • Drive the conversation: propose, explain, check in, take hints, and watch the clock out loud.

In the interview

Questions interviewers ask about this. Answer each out loud first, then compare.

Question 1

The interviewer says "Design Instagram" and stops talking. What do you do in the first two minutes?

Question 2

Why does RADIO put requirements first and optimizations last?

Question 3

How do you choose which deep dives to do?

Question 4

How does your approach differ between "design a date picker" and "design a chat app"?

Question 5

Isn't following a framework going to make your answer sound robotic?

References

Read next