You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
EDIT: Well this has been linked now so just an FYI this is still TBD. Feel free to comment if you have suggestions for improvements. Also here is an unrolled Twitter thread of a lot of the tips I talk about on here.
I've been doing frontend for a while now and one thing that really gripes me is the interview. I think the breadth of knowledge of a "Frontend Engineer" has been so poorly defined that people really just expected you to know everything. Many companies have made this a hybrid role. The Web is massive and there are many MANY things to know. Some of these things are just facts that you learn and others are things you really have to understand.
Every time I interview, I go over the same stuff. I wanted to create a gist of the TL;DR things that would jog my memory and hopefully yours too.
Lots of these things are real things I've been asked that caught me off guard. It's nice to have something you can read right before your interview so here it is. Hope this helps someone. Now obligatory, I hope you'll look at the resources section to see if you've gone through what you can. I personally didn't find the resources out there sufficient so this is what I created.
Before going through I want to call out that when in doubt, if you do not know what you will be tested on, you can never go wrong with just studying JavaScript. I have rarely ever been asked about accessibility (but have been given props for calling it out) and I have only sometimes had to build something. This is the bread and butter of almost every frontend position. I would clarify with the recruiter if you may be building something, etc but if you really are unsure and they will not give you any more details, just study fundamentals of JavaScript and maybe do some technical practice questions on Leetcode, HackerRank, etc.
This is a very large topic in frontend and I think it's worth learning the main strategies in how to optimize your website for people who are disabled. I would say a lot of what web development provides today with semantic elements is by default very accessible but we as developers sometimes choose not to use them. It's good to know what those implications are.
Don't feel like you have to memorize these but just know some fundamentals. I have rarely been asked questions about this.
Hide text visually but still available for screen readers (many ways to hide i.e. text-indent: -9999px)
Organize multiple forms with fieldset
Use headers correctly in semantic order and semantic HTML whenever possible i.e. <button> if you actually need a button
Use clear language: Avoid abbreviations and dashes if you can (replace with full word or "to") or use the <abbr> HTML element and set the title attribute to be what it stands for.
Use <label> element for controls
Avoid tab-index if you can because it can be very confusing in certain situations when users tab through
Tables, use <caption> for extra info and <th> to provide headers along with the scope attribute to specify if it's for the row or column
aria-labeledby can be powerful in having an element reference text that is already available in the DOM (set the value to the be the id of the element very similar to <label for="ID">
Omitting the alt attribute can be useful for <img> to prevent a screen reader from reading it out (useful if the image is only for visual decoration and isn't actual content.
Be cogniscent that visibility: hidden and display: none will hide content from screen readers.
Client-side validation to immediately let users know when something goes wrong
Custom controls for <video> because default controls aren't accessible
WAI-ARIA is a specification written by W3C to add HTML attributes
role communicates what the purpose of the element is useful for things like search, tabgroup, tab, alert etc
properties i.e. aria-labeledby add extra info and these generally never change
states i.e. aria-disabled communicate elements that may change in state such form fields
aria-live useful for constantly changing content
only use WAI-ARIA when you need to!
I'll be honest, I don't think I've had many interviews that have penalized me for not knowing accessibility but it has definitely helped me and impressed interviewers. However, I feel core questions have never had me talk in detail about it.
I hate to have a section for this in Frontend technical interview prep but truthfully, the role of Frontend Engineer is very vague.
Many companies distinguish the role as an engineer who works closely with service backend teams and some companies generalize the role
for the reason of "making it easy to switch around." In any case, it's useful to know these handful of algorithms regardless of what
engineering role you pursue because they are so common and fundamental.
I would say you do not need to know how to write the sorts or searches but BFS and DFS have been things I've had to implement.
Breadth-first Search (BFS)
Depth-first Search (DFS)
Binary Search
Merge Sort
Quick Sort
Before we jump into those, let's talk about Runtime analysis. Writing algorithms is good but they are reknown for a reason -- they're efficient.
Runtime Analysis
I want to make a quick section on this as this is something I see a lot of people struggle on, especially those who may not have a formal background in CS. First off, don't think you need one. And secondly, I find it is far more important to understand these runtime complexities rather than just memorize them. A double for-loop is O(N^2) but why is that? Well let's think of it in laymen's terms.
When we talk about runtime analysis, realize the reason we talk about this is to understand how something scales with regard to inputs (generally N). How does this program grow in time it takes to run?
O(1): The runtime does not change if the number of inputs change. This is effectively saying the array/list given actually has zero impact on how long it takes. An example might be you only print the first value in the array. It doesn't matter if there are 10 items or a billion items. We only look at the first one.
Similarly, if we had a program that printed the 1000th item in the array, it is still O(1) or constant time. Why is this? Because past 1000 items, the runtime does not grow and it's important to understand that. Same situation -- if we had 1000 items or a billion items, it will always take 1000 steps to get to completion.
O(N): The runtime will take longer if you increase the number of inputs. For every input, it grows the same amount. This one is pretty clear.
O(N^2): The runtime will exponentially take longer if you increase the number of inputs. For every input, you are doing everyting over again. This is why double for-loops are O(N^2). For every iteration in the first loop, we are asking it to go through another entire loop of all the inputs (this of course assumes the inner for-loop is going through the same input. If it is going through a different list, it would be considered O(N * M) where M is the second list.)
O(log N): This runtime means we are halving the time it takes on every iteration. As your input grows, it does take longer, but you are halving the time it takes. If you think of binary search, this is exactly how it works -- when given a sorted array of numbers that is converted into a BST, and a target number, you start at the root and ask yourself is the target number greater or less than the value I am on (the current iteration) and, depending on the answer, you choose and go one direction and not both ways. Eventually, you end up at the answer, but you don't explore all the inputs or even half the inputs. Every step of the tree, you are halving the decisions you are making.
Some people get confused why BST isn't O(N/2) and it's actually O(log N). My advice if you ever forget is never be afraid to just walk through the code line-by-line. If you walk through what binary search does, you'll see it goes down only one path of a tree. If we were to say O(N / 2) that would mean we explored half of the entire tree (which is not correct for large trees).
O(N log N): A lot of sorting algorithms have this as their runtime complexity. If you understand the above, it'll be easier to understand this. You can actually think of this similar to the O(N^2) where a double for-loop on every iteration we are going through all the inputs again. In this case, on every input, we look at all the inputs and then go through all of them again and halve them every step of the way again. Sorting algorithms have this runtime primarily because you need to go through all the inputs first O(N) and then based on some clever techniques i.e. in merge sort or quick sort, we can set the array up in such a way we can halve the decisions every step of the way.
One final tip, as I mentioned in the O(log N) section is never be afraid to just step through line-by-line and count how many iterations you are going through especially if you are not sure. No one will judge you for that and in fact you have to do that for far more complex programs. Don't just count the number of for-loops (I saw someone have a triple for-loop and assume they wrote their answer in O(N^3) which isn't right), step through the code and see where decisiosn are getting optimized. This is a good standard practice for coding in general to find optimizations.
With that out of the way, let's talk about some of the common algorithms you really just need to know.
Breadth-first Search (BFS)
Key thing to note is that it involves a Queue and will explore all immediate neighbors before going down the next level of nodes. For a tree, you can think of this as level-by-level and for a graph you can think of this as a ripple effect that slowly spreads.
The time you would prefer to use BFS is when you are looking for shortest path to a given node.
let visited = new Set();
let queue = new Queue();
queue.enque(root);
while (!queue.isEmpty()) {
let currentNode = queue.dequeue();
// do what you would like with the current node
console.log(currentNode);
// grab all neighbors and enqueue them
var adjacentNeighbors = getAdjacentNeighbors(currentNode);
adjacentNeighbors.forEach((neighbor) => {
if (!visited.contains(neighbor)) {
queue.enqueue(neighbor);
}
});
// mark visited
visited.add(currentNode);
}
Depth-first Search (DFS)
Can be implemented recursively or with a Stack. Be aware of stackoverflow with the recursive solution and sometimes worth calling that out with your interviewer.
As opposed to BFS, depth-first search explores a path fully first before exploring others. For a tree, you can think of it exploring one full branch to a leaf from left to right.
You would opt for DFS when you want to explore all possibilities.
function recursiveDFS(node) {
let visited = new Set();
// do something with node
console.log(node);
// mark visited
visited.add(node);
let adjacentNeighbors = getAdjacentNeighbors(node);
adjacentNeighbors.forEach((neighbor) => {
if (!visited.contains(neighbor)) {
recursiveDFS(neighbor);
}
});
}
function iterativeDFS(node) {
let visited = new Set();
let stack = new Stack();
stack.push(node);
whule (!stack.isEmpty()) {
var currentNode = stack.pop();
console.log(currentNode);
let adjacentNeighbors = getAdjacentNeighbors(currentNode);
adjacentNeighbors.forEach((neighbor) => {
if (!visited.contains(neighbor)) {
stack.push(neighbor);
}
});
// mark visited
visited.add(currentNode);
}
}
// depending if its a graph vs a tree will change what this looks like so I've given examples of what it might.
// typically a graph data structure will just have a method for getting neighbors so the example below is just what a binary tree
// might look like
// another example is a 2d array (grid) and you need to get up down left right -- that would be easier to do in it's own function!
// Output: an array of the neighbors in no particular order (but that can change depending on the problem! up to you!)
function getAdjacentNeighbors(node) {
return [node.left, node.right];
}
A few more things related to BFS/DFS
Marking visited is important to make sure you don't go exploring the same paths again. Be mindful of this and also pay attention to what the interviewer says. Directed Acyclic graphs (DAG) for example means no cycles so you do NOT have to do that for those scenarios (in the above I show marking visited even if it may not be necessary)
Binary Search
If you see a problem that specifies a sorted array and requires you to find a specific value, more often than not you can convert that sorted array into a Binary Search Tree and then search which will make the O(N) -> O(log N).
When working with trees be careful about unbalanced BSTs -- make sure you know when to traverse left or right -- don't forget some numbers can be deep down a branch and you should update your min-max ranges to the parent node potentially you are looking at.
3
/ \
/ \
1 \
\ 20
2 / \
10 \
/ 22
5
/ \
4 9
// binary search in sorted array
function binarySearch(arr, target) {
let lo = 0;
let hi = nums.length - 1;
while (lo <= hi) {
let middle = Math.floor((lo + hi) / 2)
console.log(middle)
if (nums[middle] < target) {
lo = middle + 1
} else if (nums[middle] > target) {
hi = middle - 1
} else {
return middle
}
}
return -1
}
While the above example uses JavaScript, just keep in mind a common mistake people make (as cited in EPI) is when calculating the mid value, adding lo + hi can lead to integer overflow. Read here.
Merge Sort
Stable sort which has an average/worst/best case O(N log N) sorting and takes O(N) space
Key thing to note is the merging of the array is the bulk of the implementation -- recursive case is simply splitting the array into halves until we get to the base case and compare two values together.
function mergeSort(arr) {
return mergeSortHelper(arr, [], 0, arr.length-1);
}
// recursive function to split the values
function mergeSortHelper(arr, storage, low, high) {
if (low < high) {
var mid = Math.floor((low + high)/ 2);
// sort the left and right sides respectively and recursively
var leftSort = mergeSortHelper(arr, helper, low, mid);
var rightSort = mergeSortHelper(arr, helper, mid+1, high);
// merge the arrays
return merge(arr, helper, low, mid, high);
}
}
// the actual logic of sorting the array by merging the two arrays in sorted order
// NOTE: As mentioned the space complexity is because of the `storage` we are using here
function merge(arr, storage, low, mid, high) {
// go through and shove all values we are looking at into storage
for (var i=low; i <= high; i++) {
storage[i] = arr[i];
}
var helperLeft = low;
var helperRight = mid + 1;
// start on the low and work out way up
var current = low;
while (helperLeft <= mid && helperRight <= high) {
if (storage[helperLeft] <= storage[helperRight]) {
arr[current] = storage[helperLeft];
helperLeft++;
} else {
arr[current] = storage[helperRight];
helperRight++;
}
current++;
}
// lets finish it off by filling out the rest
var whatsLeft = mid - helperLeft;
for (var i=0; i<=whatsLeft; i++) {
arr[current+i] = storage[helperLeft+i];
}
return arr;
}
Quick Sort
Unstable sort which has average case of O(N log N) but worst case of O(N^2). However it has the benefit of being able to take only O(log N) space
Involves partitioning and choosing a pivot value which you compare the values against. Once values have been compared, they are swapped in the array so they go before pivot if less in value or after if they are greater in value.
// pick a pivot and then dedicate certain sections of the array to be greater and lower than the pivot
// once "partitioned", go through each list, compare the values, and swap accordingly
function quickSort(arr) {
var left = 0;
var right = arr.length-1;
quickSortHelper(arr, left, right);
return arr;
}
function quickSortHelper(arr, left, right) {
if (left >= right) {
return;
}
var midIndex = Math.floor((parseInt(left) + parseInt(right)) / 2);
var pivot = arr[midIndex]; // just use the middle
var index = partition(arr, left, right, pivot);
quickSortHelper(arr, left, index-1);
quickSortHelper(arr, index, right);
}
// partition the array
// left and right represent the pointers on the side of the array which we compare
// against the pivot
function partition(arr, left, right, pivot) {
while (left <= right) {
while (arr[left] < pivot) left++;
while (arr[right] > pivot) right--;
if (left <= right) {
var tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
}
return left;
}
Good components to try building that you might be asked to build in an interview
While this is far less common, I have been asked to build things and while there are so many things you can be asked to build, I find that there is a specific scope of questions that can be asked. Typically these questions test how comfortable you are translating requirements into code and visuals so do not underestimate clarifying what you are building.
In general, it's probably good to build some components on your own from scratch and figure out what are some things to keep in mind when building.
Tooltip
How many will have to render on the page?
What triggers the tooltip to show?
Accessibility and what priority should screen readers read the tooltip at?
Are these informational styled tooltips?
The title attribute creates a browser default tooltip for text, worth mentioning
Localization? How will you set it up so tooltips can handle that text?
Is there an animation on how it should appear on the screen?
Boundary cases - what happens if the tooltip element should be rendered relative to a DOM element and that element is at the edge of the screen?
Login/Registration form
Expect questions to come up regarding GET/POST forms, how does the form field work?
hidden inputs will be helpful in passing data that shouldn't be shown to the user
Perhaps worth talking about how the service will handle rate limiting mass requests? CAPTCHA support?
FormData API Will make your life easier (convert an event.target and you can pick out data easier in a form related input.
Refamiliarize with form and input events i.e. focus, input, etc
Carousel
Does the carousel need to loop around?
If designing a component and no carousel items, should nothing render or placeholder?
Keyboard accessibility?
Weather widget
Clock widget
To-do list
Modal/Popup
e-commerce Cart
Datepicker
Search box
Optimizing searching when hooking into the onchange event by debouncing the requests so you don't spam the service
Show more button for a list of videos
Pagination component
Nested Dropdown
Some things to think about
Avoid id as it goes against the paradigm of componentization -- think about if this component will be used in multiple places
What parts of the component are reusable? What aren't? Don't kill yourself over this -- get something working but think about it.
Responsive layout and certain component will look in other views
Internationalization: do you have to support different languages? If so, maybe call out you'd put your text/strings in a special file that can be sent to translators and you can have some logic to determine what language the user is i.e. via the browser language settings, etc.
If there are two large items that end up getting asked in Frontend Interviews, it would be JavaScript as number 1 and then CSS as number 2. There are a lot of styling gotchas and while I don't think it's expected you can whiteboard CSS all the time, it helps to understand what CSS is doing behind the scenes so you can explain why you think the styles applied would happen this way.
Flexbox is definitely far more intuitive for formatting but I have still seen places ask about float. It's good to know these things. Here is a dump of miscellaneous things that are good to know.
JavaScript has a lot more data structures than it once did. I would heavily familiarize yourself with those if possible. These include
JSON objects and Maps (and WeakMap)
Set (and WeakSet)
Number
Array (and how to easily create a Stack/Queue from them)
It's important you understand the trade-offs, how to use them at a high-level (specific methods are less important but more that you are aware the functionality is there) to solve the problem at hand.
Things that are not natively supported but are very useful to know especially for some specific problems
Heaps (Priority Queues)
BinaryTree, Binary Search Tree
Graphs
LinkedList
HashTables (actually JSON/Maps behind the scenes are HashTables but important to know how they work)
I don't think you'll ever have to go farther than these unless it's a very niche problem i.e. using Tries/Prefix-trees for searching etc.
While I don't think you'll ever need to (or should ever need to) code these from scratch, I think it's helpful to see the implementation sometimes and their usage to get a better understanding of how they work. I will be honest, I HAVE been asked to code a data structure from scratch i.e. a Trie and a HashTable but I just don't think it's worth memorizing for. Rather, get a high-level understanding how they work and then derive it if it comes up. This repository has some great example implementations. I want to highlight and speak in depth about a few of them below:
I haven't been asked many HTML questions but if you're pursuing a web development position, this may come up more. I find there are some sort core HTML elements you should definitely know and some specific things. Here is just a dump of many of the things to remember
HTML is loaded from top to bottom. This is why we choose to prefer <script> tags on the bottom (load large bundles later and prioritize actual content), and then <style> tags.
HTML5 spec is initiated when the browsers sees the <!DOCTYPE html> at the very top
Understand the distinction of what can be done via CSS/JavaScript and what HTML is. HTML is simply the markup or the model whereas CSS and JavaScript providing the styling and the logic (Yeah sure React and many JS frameworks have made this vague but the end of the day, all of this will get outputted to HTML).
Know your <form> and how they work. Understand how it works behind the scenes (lots of magic happens of course but what makes it submit?)
It feels a little weird to separate this out into it's own section but couldn't figure a better place to do it so here it goes.
Coding on a whiteboard (generally for on-site)
When coding a whiteboard, it's easy to glaze over things but it is definitely worth practicing on a real whiteboard. If you have a friend who can let you into their office to practice in a room with a whiteboard, take advantage of it. If you have none, pencil/paper is the next best thing and practice length wise.
Some tips
Before you start coding, write down test input you'll want to try somewhere in the right corner so you know to keep it in mind but it won't get in the way
Before you start coding, in words talk with your interviewer about the thought process of how you will tackle the problem. You could start writing the function signature if you want but the investment of just thinking through the pseudo code will help you code faster.
Write small and start at the top left with extra space in between lines. You more likely than not will need to add stuff and it helps to have some space reserved
If you find yourself getting overwhelmed with a lot of the problem, break the problem up. Functions are very useful for this -- break up the logic so that you aren't tackling everything and feel free to defer things for later. It helps to have an idea of what the interviewer might be evaluating you on
Example: You have a question where you have to search for a tile on a grid/2D array and part of the problem involves looking at adjacent tiles around the tile. Naturally if you are at the edge of the grid, you'll want to make sure you aren't returning adjacents that are out of bounds. This can be broken up and deferred later (it's busy work and most likely isn't the core problem the interviewer is testing you on)
If you find yourself needing to write helper functions, don't do it under your code -- go from left to right and start high. You don't necessarily know how LONG your function will be but you can at least column them. Once you finish a function, feel free to write under then
Be smart about naming variables but don't be too verbose. Those things are trivial but most important is you write something that is clear and will help you keep track of what's going on
If tackling data structure questions, it helps to have a visualization to step through as you code. So if you're traversing a tree, draw out a tree and walk yourself through it. It also shows the interviewer more of how you think and how they should be thinking about the problem
The sad truth is, if they don't understand how your answer solves the problem, even if it does, it's a penalty on you and not them
Don't think brute force is a bad solution unless the interviewer says so -- even showing that you know how to get a brute force solution working and commenting on where the bottle necks are is good and some problems don't have a more optimal solution.
Coding on a computer (generally for phone screens)
Many frontend interviews will use some sort of repl or coding environment to test you, especially for the phone interview. Some really common ones include:
Coderpad
Codepen.io
jsFiddle
Skype Interviews
HackerRank
It's important you are familiar with the one you'll be tested on. Usually the calendar invite will have a pre-made link.
While all of these have some autocompletion or templates you can use, assume you may not be able to use them. Google for example tests people in Google Docs so
don't think it's a guarantee you'll be able to depend on IDE functionality.
Familiarize yourself with what language specific features you use. ES6 for example isn't necessarily supported and you'll need to use Babel or check if
the Node enivronment you are on supports ES6.
This is probably the largest portion of the interview that you will need to have strong fundamentals with. I highly recommend reading You Don't Know JS if you haven't already to get those fundamentals down.
Now of course these are simply "factual" things that you either know or don't. I would heavily suggest practicing technical, leetcode style questions in JavaScript as well.
Understanding of what new is actually doing (related to Prototypical inheritance)
Sync vs Async programming
Miscellaneous tips
Array.sort() sorts alphabetically by default so make sure you remember if you are sorting numbers to specify or else negatives will not sort correctly. ([].sort((a,b) => a - b))
Array.contains for arrays and String.includes for strings -- opt for these if possible over indexOf > -1 as they're clearer and easier to follow.
Queue can be simulated with Array.shift for enqueue and Array.pop to dequeue but worth pointing out that behind the scenes Array.shift is potentially an O(N) operation because arrays need to allocate space -- might be worth just asking if you can use a Queue data structure or ask if it is a concern (most likely it won't be).
Remember to Math.floor division when necessary. If you need float or decimal representations, you can use parseFloat and Number.toFixed(NUM).
While typical SWE roles heavily focus on O(N) to determine performance, frontend has their own slew of problems that can affect performance.
Having a solid understanding of networking helps a lot here but front end also has many optimizations that can be made.
Many common questions in frontend include debouncing (or rate limiting) to avoid spamming APIs or minimizing the number of DOM
elements you render (virtual lists for ridiculiusly large lists help with this). It's important to know these things because they get asked a LOT.
This list is more because I didn't feel it was necessarily appropriate to add it to other lists but I feel it adds an extra level of depth and understanding to material if you have a chance to read them.
This list is definitely not required but I find you can never stop learning. There's always new stuff popping up. I like to think that people want to bring people on that they can see as a peer and this generally means someone who they can learn from. Some of my best interview feedbacks were from people that learned something from me. I wanted to compile a list of some of the readings I feel really go a long way i.e. case studies, etc.
While you may not be asked to know everything of how the web works, there are some basic fundamentals that are worth knowing that touch networking and API design. A lot of companies view "Front-end" engineers as simply Web Engineers so it helps to know things across the entire stack.
@augbog this is a great guide, thanks for putting it together! Do you have any resources for the system design portion of a front end interview?
I've been the interviewee in a front end system design where I was asked to design a newsfeed. It was very open ended and I was asked everything from tech stack to deployment/CI pipeline and everything in between. I had to give rationale for why tech X over Y, etc. It felt similar to a traditional back end SD question but much more focused on FE.
For a more senior candidate the expectation is that you need to bring up topics rather than having the interviewer bring them up. A junior candidate might be prompted/lead more into those questions.
You had to be able to explain the trade offs for pretty much every decision
Which FE framework? Why that one rather than...?
What CSS strategy? (framework vs utilities vs naming convention vs css modules vs css in js)
REST API? GraphQL API?
How would you improve performance?
State management
Testing strategies? How would you mock API? How much coverage would you expect for your codebase?
brilliant.