Zoho Frontend Interview Questions
Fundamentals first. Several hands-on programming rounds.
Zoho builds a very wide suite of business software, largely on technology it develops itself. Its hiring, especially for freshers, is known for several rounds of hands-on programming, and it puts more weight on fundamentals and problem solving than on knowledge of a particular framework.
For frontend roles, prepare core JavaScript, HTML and CSS thoroughly, and be ready to build something without libraries. React is useful background but is often not the focus.
- Questions
- 15, 5 with free answers
- Interview rounds
- 4
- Last reviewed
- October 2026
Zoho frontend interview process
The usual shape of the loop. A guide to what to prepare, not a promise of what you will get.
- 1
Written or online round
Aptitude and basic programming questions, common in fresher hiring.
- 2
Programming rounds
One or more rounds of problems of increasing difficulty, sometimes a longer build such as a small application.
- 3
Technical interview
JavaScript, the DOM, CSS, and questions about the code you wrote in earlier rounds.
- 4
HR
Background, expectations and logistics.
What interviewers tend to look for
- Plain JavaScript and DOM work with no framework.
- Problem solving and logic, written out fully.
- CSS layout from first principles.
- Explaining and defending the code you wrote.
Your Zoho mock interview
15 questions. Type an answer under each one and an AI reviewer scores it and tells you what you missed. Stuck on one? Ask for a hint. A free account gets 3 AI replies a day.
Your mock interview
0 of 15 answered
Answer a question and your score shows up here.
JavaScript
9 questions- Question 1 of 15JavaScript
Zoho interviewer
Explain hoisting and the temporal dead zone.
Model answer
Declarations are registered when a scope is created, before any of its code runs. What differs is the starting value:
varis hoisted and set toundefined, so reading it early givesundefined.- Function declarations are hoisted with their body, so you can call them above where they are written.
let,constandclassare hoisted but left uninitialised. Reading them before the declaration line throws aReferenceError.
The stretch between the start of the scope and the declaration line is the temporal dead zone.
console.log(a); // undefined console.log(b); // ReferenceError var a = 1; let b = 2;Function expressions follow their variable:
var fn = function () {}isundefineduntil that line runs. - Question 2 of 15JavaScript
Zoho interviewer
What is a closure? Give a practical use for one.
Model answer
A closure is a function together with the scope it was created in. The function keeps access to the variables of that scope even after the outer function has returned.
function createCounter() { let count = 0; // private: nothing outside can touch it return { increment: () => ++count, value: () => count, }; } const counter = createCounter(); counter.increment(); counter.value(); // 1Practical uses: private state as above, function factories, and utilities such as
debounceandmemoize, which keep a timer or a cache between calls.The cost to mention: a closure keeps its captured variables alive for as long as the function is reachable, so a long-lived callback holding a large object is a memory leak.
- Question 3 of 15JavaScript
Zoho interviewer
How is the value of
thisdecided? How do call, apply and bind differ?Model answer
thisdepends on how a function is called, not where it is written:- Called as a method (
user.greet()): the object before the dot. - Called plainly (
greet()):undefinedin strict mode and in modules, the global object otherwise. - Called with
new: the newly created object. - Called with
call,applyorbind: whatever you pass. - Arrow functions have no
thisof their own. They use the one from the surrounding scope, and it cannot be rebound.
callinvokes the function with arguments listed one by one,applytakes them as an array, andbinddoes not invoke anything: it returns a new function withthis(and optionally leading arguments) fixed.The classic bug is passing
user.greetas a callback. The function is then called plainly and loses itsthis. - Called as a method (
- Question 4 of 15JavaScript
Zoho interviewer
How does prototypal inheritance work, and what does the
classsyntax add?Model answer
Every object has a hidden link to another object, its prototype. When you read a property that the object does not have, the engine looks on the prototype, then on that object's prototype, and so on until it finds the property or reaches
null.A function's
prototypeproperty becomes the prototype of the objects it creates withnew. That is how all arrays share one copy ofmap.classis mostly syntax over the same mechanism: methods go on the prototype,extendslinks the chain andsupercalls the parent. It does add a few real things:#privatefields, static blocks, and the rule that a class cannot be called withoutnew.Object.create(proto)creates an object with a chosen prototype directly, andObject.getPrototypeOf(obj)reads it. - Question 5 of 15JavaScript
Zoho interviewer
What is the difference between ==, === and Object.is?
Model answer
===compares without converting types.==converts first, which gives results such as'1' == 1andnull == undefinedbeing true. The one widely accepted use of==isvalue == null, which checks for bothnullandundefined.Object.isbehaves like===with two differences:Object.is(NaN, NaN)is true, andObject.is(+0, -0)is false.All three compare objects by reference, so
{} === {}is false.Worth adding in a React interview: React uses
Object.isto decide whether state or a dependency changed, which is why mutating an object in place does not trigger a re-render. - Question 6 of 15JavaScript
Zoho interviewer
What does a setTimeout inside a
for (var i ...)loop print, and how do you fix it?Model answer
for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 0); } // 3, 3, 3varis function-scoped, so there is oneishared by all three callbacks. They run after the loop has finished, wheniis already 3.Fixes, in the order you would reach for them:
- Use
let. It creates a new binding for each iteration, so the output is 0, 1, 2. - Pass the value in:
setTimeout((n) => console.log(n), 0, i). - Wrap the body in an immediately invoked function that takes
ias a parameter. This is the pre-ES6 answer.
- Use
- Question 7 of 15JavaScript
Zoho interviewer
What is event delegation? Explain bubbling and capturing.
Model answer
A DOM event travels in three phases: down from
windowto the target (capturing), at the target, then back up towindow(bubbling). Listeners run in the bubbling phase unless you pass{ capture: true }.Delegation uses bubbling: you put one listener on a common ancestor and work out which child was clicked.
list.addEventListener('click', (event) => { const item = event.target.closest('li[data-id]'); if (!item || !list.contains(item)) return; select(item.dataset.id); });Benefits: one listener instead of hundreds, and it keeps working for items added later.
Details that come up:
stopPropagationstops the event travelling,preventDefaultcancels the browser's default action, and a few events such asfocusandblurdo not bubble (usefocusinandfocusout). - Question 8 of 15JavaScript
Zoho interviewer
Write a polyfill for Array.prototype.reduce.
Model answer
Array.prototype.myReduce = function (callback, initialValue) { let index = 0; let accumulator = initialValue; if (arguments.length < 2) { // No initial value: use the first element that exists. while (index < this.length && !(index in this)) index++; if (index >= this.length) { throw new TypeError('Reduce of empty array with no initial value'); } accumulator = this[index++]; } for (; index < this.length; index++) { if (index in this) { accumulator = callback(accumulator, this[index], index, this); } } return accumulator; };The details that separate answers: checking
arguments.lengthinstead ofinitialValue === undefined(passingundefinedon purpose is valid), throwing on an empty array with no initial value, and skipping holes in sparse arrays.mapandfilterare the usual warm-ups. Both take the same(value, index, array)callback and an optionalthisArg. - Question 9 of 15JavaScript
Zoho interviewer
Flatten a nested array without using Array.prototype.flat.
Model answer
function flatten(array, depth = Infinity) { const result = []; for (const item of array) { if (Array.isArray(item) && depth > 0) { result.push(...flatten(item, depth - 1)); } else { result.push(item); } } return result; } flatten([1, [2, [3, [4]]]]); // [1, 2, 3, 4] flatten([1, [2, [3, [4]]]], 1); // [1, 2, [3, [4]]]Follow-ups: write it iteratively with a stack so that very deep nesting cannot overflow the call stack, and flatten an object into dot-separated keys (
{ a: { b: 1 } }to{ 'a.b': 1 }).
CSS
3 questions- Question 10 of 15CSS
Zoho interviewer
Explain the CSS box model and box-sizing.
Model answer
Every element is a box made of four layers: content, padding, border and margin.
box-sizingdecides whatwidthandheightmeasure. With the default,content-box, they set the content area only, so a 200px wide box with 20px padding and a 1px border takes 242px. Withborder-box, the padding and border are included in the 200px. That is easier to reason about, which is why most projects start with:*, *::before, *::after { box-sizing: border-box; }Related points that get asked:
- Vertical margins of adjacent block elements collapse into the larger of the two. This does not happen inside flex or grid containers.
- Inline elements ignore
width,heightand vertical margins.inline-blockaccepts them. outlineis drawn outside the border and does not take up space.
- Question 11 of 15CSS
Zoho interviewer
How many ways can you centre an element horizontally and vertically?
Model answer
/* 1. Grid: the shortest */ .parent { display: grid; place-items: center; } /* 2. Flexbox */ .parent { display: flex; justify-content: center; align-items: center; } /* 3. Absolute positioning, size unknown */ .child { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } /* 4. Absolute positioning with auto margins, size known */ .child { position: absolute; inset: 0; margin: auto; width: 200px; height: 100px; }Interviewers usually want you to explain one of them. In the third,
topandleftmove the child's corner to the middle of the parent, and the transform shifts it back by half of its own size, because percentages intranslaterefer to the element itself.For horizontal centring only:
margin-inline: autoon a block with a width, ortext-align: centerfor inline content. - Question 12 of 15CSS
Zoho interviewer
Explain the position values. Why does z-index sometimes not work?
Model answer
static: the default. Offsets andz-indexhave no effect.relative: stays in the flow and can be nudged. It also becomes the reference for absolutely positioned children.absolute: removed from the flow and placed relative to the nearest positioned ancestor.fixed: placed relative to the viewport, unless an ancestor has atransformorfilter, which captures it.sticky: behaves as relative until it reaches the offset you give it (top: 0), then sticks inside its scrolling ancestor. It fails without an offset, or when an ancestor hasoverflow: hidden.
z-indexonly orders elements inside the same stacking context. A new context is created by a positioned element with az-index, byopacitybelow 1, and bytransform,filterandisolation: isolate, among others.So a modal with
z-index: 9999can still sit under a header withz-index: 2, if the modal is inside a parent that forms its own context and that parent is below the header. The fix is to move the element out, usually with a portal, or to change the parent's stacking order.
Browser, performance and system design
2 questions- Question 13 of 15Browser, performance and system design
Zoho interviewer
What happens between typing a URL and seeing the page?
Model answer
- DNS turns the domain into an IP address.
- The browser opens a connection: a TCP and TLS handshake, or QUIC for HTTP/3.
- It sends the request and the server starts streaming HTML back.
- The parser builds the DOM as HTML arrives. CSS is downloaded and parsed into the CSSOM. CSS blocks rendering, and a plain
scripttag blocks the parser until it has downloaded and run. - DOM and CSSOM are combined into the render tree, which holds only what is visible.
- Layout works out the size and position of every box, paint fills in the pixels, and compositing puts the layers on screen.
- JavaScript then runs, and in a framework app it hydrates the page so that it responds to input.
This sequence is called the critical rendering path. Most performance work is shortening it: fewer and smaller render-blocking files,
deferon scripts, inlining the CSS needed for the first screen, compression, a CDN close to the user, and caching so that repeat visits skip the network.Interviewers often pick one step and go deeper, so know at least one well.
- Question 14 of 15Browser, performance and system design
Zoho interviewer
Compare cookies, localStorage and sessionStorage. Where should an auth token be stored?
Model answer
- Cookies: about 4 KB each, sent to the server with every request to their domain. They can have an expiry and security flags.
- localStorage: around 5 MB per origin, kept until cleared, shared by all tabs. Never sent to the server. The API is synchronous.
- sessionStorage: the same API, limited to one tab and cleared when it closes.
- IndexedDB: a larger, asynchronous database for structured data, used for offline apps.
For a session or auth token, the safest common choice is a cookie with three flags:
HttpOnly: JavaScript cannot read it, so a script injected through XSS cannot steal it.Secure: sent over HTTPS only.SameSite=LaxorStrict: not sent on most cross-site requests, which blocks most CSRF.
Anything in
localStoragecan be read by any script running on the page, including a compromised dependency. That is why long-lived tokens do not belong there. If a design does keep a token in JavaScript, keep it in memory and make it short-lived, with the refresh token in an HttpOnly cookie.
Machine coding
1 question- Question 15 of 15Machine coding
Zoho interviewer
Build tic-tac-toe.
Model answer
Keep as little state as possible: an array of nine cells. Whose turn it is and who has won are both worked out from the board on every render, so they can never disagree with it.
const LINES = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], // rows [0, 3, 6], [1, 4, 7], [2, 5, 8], // columns [0, 4, 8], [2, 4, 6], // diagonals ]; function getWinner(board) { for (const [a, b, c] of LINES) { if (board[a] && board[a] === board[b] && board[a] === board[c]) return board[a]; } return null; } function Game() { const [board, setBoard] = useState(Array(9).fill(null)); const moves = board.filter(Boolean).length; const player = moves % 2 === 0 ? 'X' : 'O'; const winner = getWinner(board); const draw = !winner && moves === 9; const play = (index) => { if (board[index] || winner) return; setBoard(board.map((cell, i) => (i === index ? player : cell))); }; }- Ignore clicks on a filled cell and after the game is over.
- Show whose turn it is, the winner or a draw, and a reset button.
- Cells are buttons, so the game works with the keyboard.
Follow-ups: an N by N board with K in a row to win (count outwards from the last move instead of listing lines), move history with undo, highlighting the winning line, and a computer opponent.
Practise for Zoho
Reading answers is the easy half. These problems run in the browser against real tests.
