Frontend Take-Home Assignment: How to Approach It (With Example)

Frontend take-home assignment guide: what reviewers check, how long to spend, AI rules, a worked example, a three-hour plan, a README template and common mistakes.
Author
GreatFrontEnd Team
21 min read
Nov 2, 2026
Frontend Take-Home Assignment: How to Approach It (With Example)

A frontend take-home assignment gives you a brief, a few hours or a few days, and no interviewer watching you think. That changes what is being judged. In a live machine coding round, an interviewer sees your reasoning as you work. In a take-home, the reviewer sees only what you submit: whether it runs from your instructions, whether it handles the cases the brief did not spell out, how the code is organized and what you wrote down about your choices. This guide covers what reviewers check, how long to spend, what to do about AI tools and how to handle a vague spec. It then follows one worked example, a searchable, paginated Hacker News story list, from the plan to a README you can adapt.

What does a frontend take-home assignment test, and what do reviewers look at first?

When reviewing a frontend take-home assignment, the first priority is whether the application works as expected. Beyond that, reviewers look at correctness, code quality, edge-case handling, and the overall user experience.

For senior roles, reviewers may also expect stronger architectural decisions, appropriate separation of responsibilities, meaningful tests, and clear explanations of technical trade-offs.

Evaluation priorities vary by assignment. Some place more emphasis on visual accuracy and responsive design, while others focus on code organization, testing, or maintainability. Start by identifying the mandatory requirements and evaluation criteria. Complete those first, then use any remaining time to improve the overall quality of the submission.

How long should a frontend take-home assignment take?

Frontend take-home assignments can range from a few hours to several days, depending on the role and the scope of work. Use the time estimate or deadline provided by the employer to plan your approach. If the requirements seem too large for the available time, clarify priorities rather than silently spending significantly more time than expected.

  • Respect the time limit. If the assignment specifies a time cap, work within it and prioritize the required features.
  • Ask for clarification or an extension early. If the scope or deadline is unrealistic, discuss it with the recruiter before the deadline.

Should I use AI tools on a take-home?

Policies differ by company, so the answer comes from the brief or the company's hiring page. Some companies ask candidates to complete assessments without AI. Others allow it for research if you disclose it and write answers in your own words. Some live formats now expect candidates to use AI tools. Treat a policy as specific to the format it describes, and recheck it before you rely on it, since these pages change.

A practical routine:

  1. Look for an AI statement in the brief and on the company's hiring page.
  2. If it is silent, ask the recruiter in writing and keep the reply.
  3. If AI is allowed, disclose how you used it and be ready to explain every line in the follow-up conversation.
  4. If AI is not allowed, follow the rule, since how you handle rules is part of the assessment.

What if the spec is vague, and when should I ask?

Take-home assignments may leave certain requirements open to interpretation. Before implementation, identify anything that could affect the application's behavior, architecture, or scope. Clarify important ambiguities with the recruiter or hiring team rather than making assumptions that could lead to unnecessary rework. A workable approach:

  • Read the brief twice, then write down every ambiguity. For a list with pagination: is sorting required, what happens past the last page, what counts as a result?
  • Ask once, with options. "I plan to treat results as stories only and sort by relevance unless you prefer otherwise. Is that fine?" is easier to answer than "What should I do about sorting?"
  • Check the data source before you design. Verify that the provided API can be called from your application, check its response structure, and identify any authentication or CORS restrictions before building around it.
  • Write the assumptions into the README either way. If nobody replies, the reviewer can still see what you decided and why.

The example brief used in the rest of this guide

The remaining sections use one small, invented brief. It is not from any company:

> Build a small web app that lets a user search Hacker News stories and browse the results. Use the public HN Search API (no key needed). Requirements: a search box; a list of results showing title, author, points and comment count, with each title linking to the story; pagination; sensible loading, error and empty states. Bonus: tests, accessibility, deploy. Spend about 3 hours. Add a short README covering how to run it, the decisions you made and what you would do next.

We'll use this assignment as a practical example throughout the guide, focusing on planning, implementation decisions, testing priorities, and submission quality rather than the complete application code. The timings below are a plan, not a measurement of how long the build took.

Before designing anything, call the API and read the real response. The HN Search API documents a limit of 10,000 requests per hour per IP, and the endpoint is GET https://hn.algolia.com/api/v1/search?query=<q>&tags=story&page=<n>. Calling it showed several things its documentation page does not spell out:

What the API returnedWhat it means for the build
page is 0-basedThe interface shows 1-based pages, so convert at the edge of the code
For react at 20 results per page, nbHits was 305,341 but nbPages was only 50Only the first 1,000 hits are reachable by paging. Observed on the day of writing, not documented
A query with no matches returns HTTP 200 with hits: []An empty state is a success response, not an error
A page past the end returns HTTP 200 with empty hits, and nbHits and nbPages come back as 0nbHits cannot be trusted out of range, so handle an out-of-range page on its own
"Ask HN" stories have no url key at all, not nullType url as optional and link to the HN thread when it is missing
The response sends access-control-allow-origin: *A browser can call the API directly, with no proxy

Each row is something a reviewer finds by clicking around, and each becomes an edge case below. The example uses this API instead of GitHub's search API because unauthenticated GitHub search allowed 10 requests per minute, which would make a debounced search fragile while a reviewer clicks around.

How do I plan a three-hour frontend take-home assignment?

Here is one way to divide the three hours.

TimeWhatCommit
0:00 to 0:15Read the brief twice. Write the edge-case list. Decide scope. Send any question now.none, notes only
0:15 to 0:30Call the API with curl and read the real response. Scaffold Vite, React, TypeScript and Vitest."Scaffold app and check API shape"
0:30 to 1:15API layer, search with loading, error and success, the list. Make it work first."Search and results list"
1:15 to 1:50Query and page in the URL, pagination, empty and out-of-range handling."Pagination and URL state"
1:50 to 2:25Four tests on behavior, not implementation."Tests for states and stale responses"
2:25 to 2:45Accessibility pass (keyboard, labels, live region, focus) and a manual edge-case pass in the browser. Light styling only."A11y and edge-case fixes"
2:45 to 3:00README, delete dead code, clone fresh and follow the README steps."README"

Checking the API early prevents the biggest surprises, and the last 15 minutes are for the README and a fresh-clone run.

Which technical decisions matter most in a take-home?

A take-home is small enough that a reviewer can see every decision. The ones below carried the most weight in the example, with the trade-off behind each. These are the choices to put in your README.

DecisionWhat the example doesTrade-off
How to model request stateOne status of loading, error or success instead of separate booleansA single status cannot be two things at once, so the interface cannot render an impossible combination. It is slightly more typing than two booleans
Stale responsesCancel the previous request when the query or page changes, and ignore any late resultDebouncing makes the race rarer but not impossible, so the example keeps both. GreatFrontEnd's 3 years machine coding guide explains the race and the AbortController fix in detail
Where the query and page liveIn the URL, with replaceState while typing and pushState for page changesA refresh, the Back button and a shared link all work, and a reviewer can type ?q=react&page=2 to test edge cases. Typing with replaceState keeps Back from filling with one entry per keystroke
What knows about the APIOne file owns the URL and the response shapeA change to the API touches one place, and the Ask HN quirk is handled once. It adds a file the brief did not ask for
How the component gets its dataThe search function is passed in as a prop, defaulting to the real oneTests control timing exactly and never touch the network. It is a small abstraction, so name it in the README
DependenciesReact and TypeScript on Vite. No UI library, state library or routerFor a small, single-screen application, fewer dependencies can reduce setup complexity and make the implementation easier to review. Additional libraries should solve a specific need rather than add unnecessary abstraction

Prioritization is the skill underneath all of this. With limited time, prioritize the explicit requirements first, followed by critical edge cases and verification. Reserve time for a clear README, and only add extra features when the essentials are complete. A smaller, working submission is better than an ambitious one that cannot be run or evaluated.

Which edge cases and accessibility details are worth my time?

Write the edge-case list before you write code, then check each item in the browser before you submit. For the example, the list is:

  • empty query (the example shows the latest stories)
  • a query with no matches
  • special characters in the query
  • a failed request, with a way to retry
  • a slow response that arrives after a newer one
  • a page number past the end, typed into the URL
  • a story with no external URL

Two of these needed product decisions, not just code. The 1,000-hit ceiling means the interface should not promise 305,341 results that the Next button can never reach, so the example says how many are browsable. A page past the end shows "There is nothing on page N" with a "Back to page 1" button instead of a blank screen.

Accessibility should be considered during implementation, not treated as a last-minute addition. For this example, that means using semantic HTML, labeling controls, supporting keyboard navigation, communicating loading and error states, and managing focus when the page changes. The checklist below is general practice applied to the example, with how each item was verified:

ItemWhat the example doesHow it was checked
Labeled inputA <label> linked to the input, with role="search" on the formThe tests find the input by its label, which only passes if the link works
Native elements<button> for Next, Previous, Try again and Back to page 1, <a> for stories, <ul> for the list, <nav aria-label="Pagination">Code reading, plus role queries in the tests
Announced loading and countsOne role="status" live region for loading and result counts, role="alert" for errorsCode reading and role queries. Not run with a screen reader
Focus after a page changeThe results heading is focusable and receives focus when the page changesChecked in a real browser: after clicking Next, the active element was the heading
Boundary buttonsPrevious disabled on page 1, Next disabled on the last pageCode reading

Three things were not checked, and a README should say so when it makes accessibility claims: no screen reader was run, colour contrast was not measured because the demo is unstyled, and only one browser was used. Two shortcuts are also worth owning instead of hiding: aria-current="page" sits on a text span rather than on a link in a list of page links, and links opening in a new tab do not warn the user. Both belong under "what I would do with more time". For more background on what interviewers expect, see GreatFrontEnd's guide to accessibility interview questions for 3 years experience.

Should I write tests, and how many?

Whether tests are mandatory depends on the assignment requirements. If the brief requires tests, include them. Even when tests are optional, a few focused tests can demonstrate that you've considered important user flows, failure scenarios, and edge cases. Prioritize tests that verify meaningful behavior rather than implementation details.

The example has four tests, each covering something a reviewer would try by hand:

  1. loading, then results, then Next page, with the page in the URL
  2. a failed request, then a retry
  3. a slow response for an old query arriving after a newer one
  4. an empty state that names the query

The testing decisions matter more than the test code:

  • Query by role and label, not by implementation. The tests use Testing Library queries by role and label, so they check what a user can see and survive a refactor. The frontend testing interview questions for freshers cover the broader picture.
  • Control time instead of waiting. The stale-response test resolves each fake request by hand, in the wrong order, so the race happens on purpose.
  • Break the code once to prove the test can fail. A test that passes the first time proves little. In the example, the guard that ignores late results and the cancellation in the cleanup were removed, and the stale-response test failed while the other three still passed.
  • Skip what you cannot defend. The example does not test styling or implementation details, and the README says so.

How should I structure the repo and the commits?

Make the structure answer the reviewer's first question, which is "where is the fetch?". The example uses one file per responsibility and nothing the brief does not need:

hn-story-search/
README.md
package.json
vite.config.ts # includes the Vitest config
src/
api/hn.ts # the only file that knows the URL and response shape
hooks/ # request lifecycle, and query + page in the URL
components/ # the search page, the list, pagination, and the tests

Use small, descriptive commits to keep your work organized and make changes easier to understand. A clean commit history can also help you explain how the implementation evolved during a follow-up discussion. You don't need a commit for every minor change, but avoid submitting a confusing history if the repository is part of the deliverable. The commands behind a clean history are in the Git interview questions for frontend developers.

What goes in the README?

A clear README helps reviewers understand and run your submission without having to explore the entire codebase. Include setup instructions, a summary of the implemented features, important technical decisions, assumptions, known limitations, and what you would improve with more time. Here is the example's, written in the candidate's voice:

# HN story search
Search Hacker News stories and browse results, built for the [company] frontend take-home.
## How to run
Developed on Node 24.16.0 and npm 11.13.0.
npm install
npm run dev # open the URL Vite prints
npm test # 4 tests, no network needed
npm run build # typechecks, then builds
No API key is needed. The app calls the public HN Search API
(https://hn.algolia.com/api), which is documented as limited to 10,000
requests per hour per IP.
## What it does
- Search box with a 300 ms debounce. Results show title, author, points,
comment count; titles link to the story (Ask HN posts link to the HN thread).
- Pagination (20 per page). The query and page live in the URL, so a refresh,
the back button, and a shared link all work.
- Loading, error (with Try again) and empty states. A page past the end shows
a "Back to page 1" button.
## Decisions and trade-offs
- **React + TypeScript + Vite, no UI library, no state library, no router.**
The brief is one screen. Fewer dependencies means less to review, and I wanted
the data flow to be easy to follow.
- **State in the URL, not in component state.** Pagination state is shareable and
survives refresh. Typing uses `replaceState` so the Back button is not filled
with one entry per keystroke; page changes use `pushState`.
- **One `status` value (loading / error / success) instead of separate booleans**,
so impossible combinations cannot be rendered.
- **Cancel the previous request when the query or page changes**, and ignore
late results. Debouncing makes the stale-response bug rarer, not impossible, so I
kept both.
- **The API layer is injected into the component**, so tests control timing
exactly and never hit the network.
- **Tests cover behaviour a reviewer would try by hand**: loading to results to
next page, error then retry, a slow response arriving after a newer one, and
the empty state. I did not test styling or implementation details.
## Assumptions
- "Results" means stories only (not comments).
- Sorting by relevance (the API default) is fine; the brief did not ask for a sort.
- The first 1,000 hits are enough: the API does not let you page beyond that
(observed: 305,341 hits for "react" but 50 pages of 20). The UI says so.
## Known limitations / what I would do with more time
- No visual design pass: it is unstyled apart from browser defaults.
- Add a "sort by date" control (the API has `search_by_date`).
- Add a Playwright test for the keyboard flow and screen-reader names; I checked
keyboard focus after paging by hand but did not run a screen reader.
- Cache recent queries (or use TanStack Query) if this were a real app.
- Show a rate-limit-specific message if the API ever returns 429.
- Deploy a preview.
## Time spent
About 3 hours [replace with your honest number].

Two details are worth copying. The Assumptions block turns a vague spec into decisions the reviewer can agree or disagree with. The Known limitations block shows you saw the gaps, which is better than hoping nobody notices. Before you submit, follow your own README on a fresh clone. If it does not run from your instructions, nothing else in the repo matters, which is the first thing a reviewer checks.

Should I add extra features, and what mistakes sink a frontend take-home assignment?

Resist extras until every explicit requirement is done. A useful test: an idea that accomplishes or improves the stated requirements is probably worth it, and one that is merely cool or tangential is probably scope creep. Be mindful of time spent on primary features versus additional ones. Make it work, then make it pretty, then make it fast.

Common mistakes to avoid:

  • Skipping edge cases. Test empty inputs, special characters, no results, invalid responses, and failed requests.
  • Adding unnecessary dependencies. Every library should solve a specific need, as in the decisions table above.
  • Incomplete setup instructions. Follow your own README on a fresh clone before you submit.
  • Including unnecessary files. Exclude node_modules, generated build output, and other files that don't belong in the submission.
  • Putting secrets in client code or in the repo. Vite's environment variable docs say VITE_* values are bundled into the client source and should not contain sensitive information such as API keys. Keep *.local files out of git. If a secret does get committed, revoke or rotate it first, because deleting it from the latest commit does not remove it from history.
  • Ignoring repository visibility requirements. Check whether the assignment requires a private repository or allows a public submission. Some companies prohibit publishing take-home solutions, so confirm the instructions before pushing your code to GitHub.

How do I submit, and what happens in the follow-up call?

Before you submit, run through a short checklist: clone fresh and follow the README, delete dead code, check that no secrets or build output are in the repo, confirm the repo visibility the brief asks for, and note your honest time spent.

Some companies schedule a follow-up discussion after reviewing your assignment. You may be asked to explain your architecture, justify technical decisions, discuss limitations, or make a small change to your implementation. Be prepared to explain why you chose a particular approach, what alternatives you considered, and what you would improve with more time.

Preparing for it is mostly about defending your own work:

  • Re-read your code the evening before and note the three decisions you would defend and the two you would change.
  • Know every dependency in package.json and why it is there.
  • Practice a small live change: add a filter, change the page size, handle a new error.
  • Be honest about what you did not check. The README's limitations list is the script for that.

This is also where the machine coding skills from live rounds come back. GreatFrontEnd's machine coding round guide covers how to explain a UI build out loud, and a mock interview is a good way to practice the walkthrough.

When is it reasonable to push back on the take-home itself?

Sometimes, and politely. Many employers are open to a candidate who raises concerns about unpaid work or asks for more time, and some will offer an alternative. Reasonable requests:

  • Ask for a time cap in writing, so you know what "done" means.
  • Ask whether a person will review the submission and whether a follow-up conversation is planned.
  • Ask whether an alternative format, such as a live session or a review of existing work, is available if you cannot give the time.

None of these guarantees a yes. A reasonable employer can say no, and you can decide whether the role is worth the hours. The point is to decide with information, not to discover the cost at hour ten.

Frequently asked questions

Is a frontend take-home assignment harder than a live coding round? It is different. You control the clock and can use your own tools, but the reviewer judges only the result, so the README, the structure and the edge cases carry more weight.

Should I use TypeScript on a frontend take-home? If the brief names a stack, use it. If it does not, use the one you can write fastest and explain best. The example uses TypeScript because typing the API response is what exposed the missing url key on Ask HN stories.

Should I deploy it? If deployment is required, include it. Otherwise, prioritize completing the assignment and ensuring it runs locally from the README instructions. A live preview can be a useful bonus when time permits.

What if I run out of time? Prioritize completing the most important requirements. If you cannot finish everything, submit the working parts and clearly document what remains, the assumptions you made, and what you would implement next.

Can I reuse a boilerplate or starter? Check the assignment rules. If starter templates are allowed, use one that helps you focus on the requirements without adding unnecessary complexity. Be transparent about what you built yourself.

How to prepare for a frontend take-home assignment

  1. Build one small app from a blank folder before you need to: fetch, loading and error states, a URL-driven list. Use the decisions table in this guide as a checklist.
  2. Practice writing a README at the end of every project, including a "what I would do next" list.
  3. Learn to test a component by role and label, so writing four tests takes minutes.
  4. Keep a short edge-case list you reuse: empty, error, slow, out of range, special characters.
  5. Run a timed rehearsal at the cap you expect, and note what you cut.
  6. Practice explaining your code out loud, to a friend or to a rubber duck.

Conclusion

A frontend take-home assignment usually rewards the same things: it runs from your instructions, it does what the spec says, it handles the edge cases around it and it is easy to read. After that, assignments differ on tests, accessibility, polish, time and AI, so the brief in front of you decides. The example in this guide shows one way to meet that bar in about three hours of planned work: check the API first, keep state in the URL, cancel stale requests, test behavior and write a README that states your assumptions and your gaps. Do the explicit requirements first, document what you chose and what you skipped, and be ready to talk about every decision.

Related articles

Machine Coding Round: The Complete Frontend Guide (2026)A frontend-focused guide to machine coding round questions, including what is machine coding round, how to prepare for machine coding round interviews, and how to practice in React.
Machine Coding Interview Questions for 3 Years ExperienceMachine coding interview questions for 3 years experience: what changes at mid-level, a worked filterable list problem, async state, races, and cleanup.
Frontend Mock Interview: How to Practice and What to Simulate (2026)Run a useful frontend mock interview with realistic timing, prompt selection, scoring signals, feedback notes, and a repair plan for the next session.
Frontend Testing Interview Questions for Freshers: 30 Must-Know (2026)Prepare for frontend testing interviews with 30 fresher questions on unit, integration, E2E, React Testing Library, mocks, async tests, coverage, CI, and accessibility.