You'll build a small Pokédex interface that searches for and displays Pokémon data fetched live from a public API. The goal is not pixel-perfect polish — it's working, readable code that handles the real-world messiness of async data and dynamic UI state.
You may use any language that runs in the browser (HTML/CSS/JS, TypeScript, etc.) and any tooling you're comfortable with. Frameworks are permitted but not required. What matters is your approach, not your setup.
Before you begin: The PokéAPI is a free, public, no-auth API. No API key is needed. Base URL:
https://pokeapi.co/api/v2/— you will primarily use the/pokemon/{name-or-id}endpoint. Take 2–3 minutes to inspect a response in your browser before writing any code.
Implement all four of the following. Each requirement notes the specific detail that will be checked during review.
A text input and submit trigger (button or Enter key) that accepts a Pokémon name (e.g. pikachu) or numeric ID (e.g. 25). Input should be trimmed and lowercased before the request is made.
On a successful response, render:
- The Pokémon's name and ID number
- Its front sprite — use
sprites.other["official-artwork"].front_defaultif you can find it in the response, otherwise fall back tosprites.front_default - Its types as styled badges (e.g. fire, water, grass)
- Its base stats (HP, Attack, Defense, Speed) as labeled visual progress bars — not plain numbers
While a fetch is in flight, show a visible loading indicator. If the API returns a non-2xx response or the name is invalid, show a clear, user-facing error message. The previous card (if any) should be replaced, not stacked.
A second button that generates a random integer between 1 and 1010 and fetches that Pokémon. It should use the same fetch logic and states as the search input — no duplication of fetch code.
Only attempt these if you finish the four requirements with time to spare. Do not sacrifice a working core for a partial stretch feature.
Stretch Goal A — Recently Viewed
Maintain a "recently viewed" row below the card showing the last 5 Pokémon searched (name + sprite thumbnail), each clickable to reload that Pokémon. State lives in memory only — no localStorage required.
Stretch Goal B — Type Matchup Below the stats, display a small section showing the Pokémon's weaknesses (types that deal 2× damage). This data is available via a second API call to the type endpoint returned in the Pokémon response.
| Field | Notes |
|---|---|
GET /pokemon/{name} |
Primary endpoint. Accepts name (lowercase) or numeric ID. Returns 404 for unknown names. |
sprites.front_default |
Standard sprite URL. For higher quality, look in sprites.other["official-artwork"].front_default. |
types[].type.name |
Array of type objects. Most Pokémon have 1–2 types. Examples: fire, water, grass, psychic, dragon. |
stats[].base_stat |
Array of stat objects. stat.name gives the label ("hp", "attack", etc.). Values typically range 1–255. Treat 255 as 100% for your progress bars. |
| Time | Activity |
|---|---|
| 0–3 min | Read this document. Open https://pokeapi.co/api/v2/pokemon/pikachu in your browser and scan the JSON response shape before writing a single line of code. |
| 3–8 min | Set up your file(s) and scaffold the HTML structure. Get a working fetch call in place that logs the response to the console. |
| 8–20 min | Implement Requirements 1–4. Fetch logic first, then render, then loading/error states, then the Random button. |
| 20–27 min | Polish edge cases: empty input, rapid re-submits, slow network. Ensure the UI doesn't break on repeated searches. |
| 27–30 min | Stretch goals if time permits. Otherwise, review your code for obvious cleanup — naming, dead code, any TODO comments. |
✅ What's allowed
- Any browser-native APIs (fetch, DOM, CSS)
- Any framework or build tool you choose
- MDN documentation or the PokéAPI docs
- TypeScript if you prefer it
We know 30 minutes isn't long. We're not expecting a finished product — we're watching how you think. If you hit a wall, talk through what you're doing. If you make a trade-off, name it. A working search with a good error state beats a half-rendered card with no loading indicator every time.
Good luck