Staff UI Engineer
Course Description
Prepare yourself for intensive frontend interviews at companies like Meta, Amazon, and Netflix! Work through complex JavaScript, TypeScript, and UI Component challenges while learning strategies for approaching onsite and take-home assignments. From writing a throttle algorithm to creating a basic Google Sheets application, this course helps junior, senior, and staff-level engineers land that dream job!
Prerequisite: This advanced course requires
Intermediate TypeScript experience along with comfort writing object-oriented code in
Vanilla JS or
React
Preview
Course Details
Published: April 9, 2026
Learning Paths
Learn Straight from the Experts Who Shape the Modern Web
Your Path to Senior Developer and Beyond
- 250+ In-depth courses
- 24 Learning Paths
- Industry Leading Experts
- Live Interactive Workshops
Table of Contents
Introduction
Section Duration: 13 minutes
Evgenii Ray introduces himself and outlines the workshop structure, which is 80% hands-on coding, and previews the challenges covered, ranging from warm-up TypeScript questions to advanced problems like building a ChatGPT-like interface and a Google Sheets clone.
Evgenii outlines the course format, describing how the problems are structured and their varying complexity. The course repo is provided, and Evgenii walks through the process of solving each challenge and verifying the results with the provided tests.
Easy JS/TS Problems
Section Duration: 36 minutes
Evgenii emphasizes the importance of understanding problem requirements before coding and discussing multiple solutions and space/time complexity with the interviewer. He then walks through the detectType problem, demonstrating how to determine the type of a JavaScript value using its constructor function and prototype.
Evgenii explains the debounce problem and its practical applications in scenarios like search bars and button functionality. He walks through the solution approach, covering how to cancel and reschedule timers, use arrow functions for context, and properly type the debounce function in TypeScript.
Evgenii kicks off the first TypeScript challenge, walking through how to build a generic type called Length that takes a read-only tuple and outputs its length. He demonstrates how to use a read-only array to infer its size and return it as a type. Evgenii then presents the challenge of extracting the first type from a tuple.
Evgenii explains throttle, how it differs from debounce, and where it applies in scenarios like limiting fire rate in a game. He walks through the implementation, demonstrating how to store the last function execution time and use comparison logic to decide whether to run the function.
Medium JS/TS Problems
Section Duration: 1 hour, 1 minute
Evgenii covers the concept of ES5 extends, explaining how to build a function that mimics prototype-based inheritance in JavaScript. He walks through the code, demonstrating how to establish the prototype chain and link static variables to create a successful extension between two classes.
Evgenii presents the tuple to union challenge, demonstrating how to convert a tuple array into a union type using index notation. He then moves on to the Pick challenge, guiding students through limiting a generic to keys of an object and remapping properties to construct a new object from the selected keys.
Evgenii presents the deep equals problem, explaining the need to compare deeply nested objects and arrays while handling circular references. He walks through the implementation, demonstrating how to compare types, keys, and values recursively and use a cache to prevent infinite recursion.
Evgenii presents the deep clone problem, explaining the need to clone values deeply, handle special types like Map, Set, and Date, and manage circular references. He walks through the logic, demonstrating how to use a cache to store cloned values and differentiate between objects and primitives.
Evgenii walks through the TypeScript challenge of implementing a generic Readonly type that takes an object and makes all its fields read-only at the type level. He then moves on to the tuple to object challenge, demonstrating how to convert a read-only tuple array into an object by iterating over the array and assigning keys and values.
Evgenii presents the challenge of implementing JSON.stringify with circular reference support, walking through how to handle different data types like null, numbers, booleans, strings, symbols, and dates. He then demonstrates how to handle complex types like objects, maps, arrays, and sets while managing circular references using a cache.
Hard JS/TS Problems
Section Duration: 1 hour, 8 minutes
Evgenii covers the fundamentals of promises, explaining how they start in a pending state and transition to fulfilled or rejected via resolve and reject functions. He walks through properly typing the executor function, onFulfilled and onRejected callbacks, and the handlers stored in the promise.
Evgenii explains the process of checking if a value is a promise and updating the promise state based on its status. He then walks through implementing the then method, demonstrating how to create new promises and establish links between them to support chaining.
Evgenii covers the Execute function, explaining how it iterates over handlers and executes them in the microtask queue based on fulfilled or rejected status. He walks through wrapping handler execution in a try-catch block, handling exceptions by rejecting immediately, and verifies the implementation by running tests.
Evgenii presents the Append to Object TypeScript challenge, demonstrating how to create a type that adds a new field to a target object by iterating over existing keys and updating the union. He then walks through the Merge challenge, showing how to merge two types while prioritizing values from the second object when keys overlap.
Evgenii explains the tree selection problem, covering the hierarchy of checkboxes and how selection propagates up and down the tree. He walks through constructing a tree-like structure from input paths and handling bubbling and propagation of events to return the expected output.
Evgenii covers the concepts of bubbling and propagating in a tree structure, demonstrating how to use generators to output parents and children. He walks through handling clicks on tree nodes, updating statuses, and propagating changes up and down the tree before running tests to verify the implementation.
Easy Component Problems
Section Duration: 1 hour, 19 minutes
Evgenii covers the differences between classic vanilla problems and component problems, emphasizing the importance of user interactions, data models, API design, and accessibility. He demonstrates how to solve component problems in vanilla by building an abstract component class and implementing lifecycle methods like init, render, and destroy.
Evgenii presents the accordion component, explaining its structure and requirements including accessibility support and unique properties for each item. He demonstrates how to implement it using native HTML elements like details and walks through styling the component for a polished appearance.
Evgenii presents the star rating problem, explaining its requirements including support for controlled, uncontrolled, and read-only modes. He walks through the implementation, demonstrating how to render stars using buttons and set accessibility attributes like ARIA roles and data properties for each star.
Evgenii walks through the click event handler for the star rating component, demonstrating how to assign a new value to state based on the target's dataset rating and refresh the display by calling render. He then debugs a styling issue with the pointer display, identifying and correcting an incorrect calculation in the data-checked attribute.
Evgenii presents two TypeScript challenges, first walking through how to detect the type never by wrapping it in an array to convert it into a union. He then moves on to the AnyOf challenge, demonstrating how to build a utility type that checks whether a tuple contains at least one truthy value using the infer keyword.
Evgenii presents the reusable tab component challenge, explaining that clicking a tab should render its content while keeping only one panel visible at a time. He walks through setting up state in the constructor and rendering tab buttons and content based on user interactions, with correct ARIA roles for accessibility.
Evgenii presents the challenge of building a dialog element, emphasizing the importance of focus management and event handling. He demonstrates how to use the native HTML dialog element to simplify implementation, walking through how to open, close, and handle confirm and cancel events with proper accessibility support.
Evgenii presents the Lookup challenge, demonstrating how to extract a specific type from a union based on a shared property using conditional types. He then walks through the ReturnType challenge, showing how to use infer to extract the return type from a function.
Medium Component Problems
Section Duration: 1 hour, 21 minutes
Evgenii presents the tooltip challenge, explaining how to build a tooltip with auto-positioning based on available space around the trigger element. He walks through rendering the tooltip in top, bottom, left, and right positions by adjusting coordinates and demonstrates static tooltip rendering before moving into the full implementation.
Evgenii covers the ShowTooltip and HideTooltip methods, walking through how they assign position classes and toggle tooltip visibility via the display property. He demonstrates wiring these methods to mouse and keyboard events and adjusts CSS classes to ensure correct tooltip positioning across all placements.
Evgenii covers the auto-positioning logic for tooltips, explaining the importance of verifying candidate positions against viewport boundaries using getBoundingClientRect. He walks through calculating and validating tooltip positions for left, top, right, and bottom placements, debugging calculations to ensure correct rendering.
Evgenii presents the concept of implementing a generic data table in React, explaining the need for sorting, pagination, and filtering. He walks through the required properties, including columns with unique identifiers and renderers, a data source interface, a search function, and a comparator for sorting.
Evgenii explains the nextDirection utility and how it determines the next sort direction based on the current one. He walks through setting up state for the query, fetched data, and sort state, then demonstrates fetching initial data with useEffect and handling data caching to optimize performance.
Evgenii presents the search functionality, demonstrating how to filter data based on a user-provided query and handle query changes with a search box. He then walks through implementing pagination, covering how to handle next and previous page clicks while keeping the current page within allowed bounds.
Evgenii presents a TypeScript challenge where students extract a parameter type from a function using the infer technique, walking through the implementation step by step. He then presents the Reddit Thread problem, guiding students through rendering a recursive comment thread component in React using a details stack.
Evgenii presents the challenge of building a custom gallery component in React, explaining the approach of lazy loading images and enabling navigation between them. He walks through tracking the current index, handling previous and next buttons, and rendering images with basic styling and animations.
Hard Component Problems
Section Duration: 1 hour, 39 minutes
Evgenii introduces the Toast problem, explaining the goal of building a component that displays informative messages with a set duration and fade-in/fade-out animations. He walks through the solution approach, covering the use of the animationend event for safe element removal and the importance of accessibility features like role="status" and aria-live.
Evgenii covers the process of creating toast elements with unique IDs and walks through building the main container with proper accessibility attributes like aria-live and aria-relevant. He then demonstrates rendering toast elements, applying fade-in and fade-out animations, and using the animationend event to cleanly remove elements from the DOM.
Evgenii presents the Capitalize TypeScript challenge, walking through how to use the extends keyword for pattern matching and the Uppercase utility type to capitalize the first letter of a string. He then moves on to the TrimLeft challenge, demonstrating how to remove leading spaces using pattern matching and recursion.
Evgenii covers the calculator component implementation using a modular pattern, walking through the layout elements and actions defined for each button. He covers implementing actions like adding numbers, applying operators, clearing the formula, calculating results, and negating values.
Evgenii walks through the calculator UI, covering how to define the layout as a section, render buttons by iterating over them, and display the current state using CSS grid. He then demonstrates implementing event delegation to handle button interactions efficiently with a single event listener, highlighting it as an expert technique worth showcasing in interviews.
Evgenii presents the 8-Puzzle Game, explaining the concept of rearranging numbered squares with one empty cell to achieve a winning order. He walks through creating the game state, randomizing it, converting it into a 2D array, and validating the win condition based on the order of values.
Evgenii covers the move validation logic, explaining how to check for valid vertical and horizontal movements based on coordinates. He then walks through generating the UI elements, rendering numbers on the grid, and styling the game board, including differentiating the empty cell with specific CSS attributes.
Evgenii covers the event handling logic, walking through the handleClick and handleCellClick functions and the verifications required within each. He demonstrates modifying the game state by swapping cells using structured cloning and destructuring assignment, ensuring moves are validated before updating the state.
Evgenii presents a TypeScript challenge where students replace a specific word in a string with another using pattern matching via the extends keyword. He discusses how this technique can be applied in production to dynamically generate string values for class typing in TypeScript.
Extreme Component Problems
Section Duration: 2 hours, 16 minutes
Evgenii presents the portfolio problem, explaining the need to visualize a complex financial tree structure with nested allocations and values. He walks through the components and properties needed and guides students through implementing the UI to render the portfolio data.
Evgenii covers the follow-up requirements for the portfolio problem, explaining the rules and constraints around editing nodes. He walks through applying a normalization technique to pre-process the tree structure, demonstrating how to construct a normalized map for efficient data handling.
Evgenii implements the keyboard event handler using event delegation, registering a single handler at the top level div rather than on every child node. He walks through the first budgeting constraint, validating that a parent node cannot be reduced below the sum of its children values.
Evgenii continues building out the budgeting rules, adding the second constraint that prevents a child node from exceeding the available unallocated cache. He also optimizes the node structure, sets up the input ref with a useEffect for syncing values, and adds the unallocated cache display.
Evgenii debugs the max allowed cache calculation, fixes the formula for computing sibling sum, and walks through each budgeting constraint to verify they all work correctly. He wraps up with a recap of the full solution and answers a student question about what to expect in a real interview setting.
Evgenii presents the ChatGPT client problem, explaining the need to create a basic version that accepts text input and returns dynamic server responses, including a markdown engine to parse binary text into HTML. He walks through applying regular expressions to match and convert markdown elements like headings, links, and lists into HTML tags.
Evgenii walks through implementing the replacer functions for links, headings, and other elements, demonstrating how to replace markdown with the correct HTML. He covers parsing bold, italic, strikethrough text, and ordered and unordered lists, then wraps up by building the classes and rules that power the markdown engine.
Evgenii sets up the ChatGPT clone UI in React, building the chat content and controls layout with basic CSS grid styling. He connects the useMarkdownStream hook, confirms chunks are arriving in state, and wires up the Markdown component for rendering.
Evgenii builds the type function that mimics a typing effect by slicing chunks and scheduling renders with requestAnimationFrame. He works through the initial implementation and begins debugging why the effect isn't behaving as expected.
Evgenii refactors the chunking logic by moving state management into the useEffect, resolves the remaining bugs, and gets the typing effect working correctly. He finishes by adding auto-scroll behavior to the chat container and recaps the full solution.
Final Boss Problem
Section Duration: 1 hour, 48 minutes
Evgenii presents the final boss problem, a simplified Google Sheets clone, outlining the supported features like arithmetic operations and cell references, and the provided tools for AST building and reverse polish notation conversion. He discusses the need to decompose the problem and implement an engine to drive the UX.
Evgenii walks through the class structure, explaining the maps used to store values and dependencies, including fields like cell ID, value, dependencies, reverse dependencies, and compiled. He covers initializing the class, creating getters and setters for cell values, and the importance of lazy initialization for handling dependencies efficiently.
Evgenii explains the process of compiling row values, covering how to check if input is a formula, tokenize it, convert it to reverse polish notation, and set dependencies accordingly. He demonstrates how to update dependencies by removing old ones and adding new ones, then connects it all together by calling the compile function within the set row value process.
Evgenii covers the concept of topological ordering, explaining how it determines the correct execution order based on cell dependencies. He walks through constructing the topological order using reverse dependencies and in-degree maps, and demonstrates identifying cyclic dependencies while testing the algorithm for correctness.
Evgenii explains how the evalRPN function processes reverse polish notation to return an evaluated string, and how the resolve method retrieves actual values from the engine. He walks through implementing the evaluation pipeline, checking for errors in the compiled RPN notation, and returning the final cell value.
Evgenii covers the process of recomputing values in the engine, explaining how to iterate over cyclic dependencies and mark them as invalid. He demonstrates how to move through the order array, calculate new values, and assign them to cells while excluding those present in their own cyclic dependencies.
Evgenii walks through building the cell component, including proper ARIA roles, class names, and content editable behavior. He then sets up the header rows and body rows, renders the full grid, and adds column resizing while deliberately bypassing React's update lifecycle for performance.
Evgenii implements focus and blur event handlers to enable formula parsing on the spreadsheet cells. He works through debugging the cell update logic and demonstrates the finished spreadsheet with chained formula dependencies and cycle detection.
Wrapping Up
Section Duration: 1 minute
Evgenii covers performance optimization by preparing header and body rows statically to bypass React state and avoid unnecessary re-rendering. He demonstrates rendering the table and handling focus and blur events, then closes the workshop by emphasizing the importance of tackling complex problems in today's competitive market.