Salesforce Frontend Interview Questions
Web standards, JavaScript depth and accessibility.
Salesforce's UI platform is Lightning Web Components, a framework built directly on web standards: custom elements, shadow DOM, templates and ES modules. Frontend interviews therefore lean towards standard JavaScript and the browser platform more than towards React-specific APIs.
Candidates commonly describe a coding assessment, technical rounds on JavaScript and problem solving, a design discussion and a hiring manager round. Accessibility comes up often, since Salesforce sells to large enterprises and governments.
- Questions
- 15, 5 with free answers
- Interview rounds
- 4
- Last reviewed
- October 2026
Salesforce frontend interview process
The usual shape of the loop. A guide to what to prepare, not a promise of what you will get.
- 1
Online assessment
Coding problems, usually data structures and algorithms.
- 2
Technical rounds
JavaScript fundamentals, problem solving, and the DOM and event model.
- 3
Frontend or design round
Component design, the web platform and how you would structure a feature.
- 4
Hiring manager
Past work, collaboration and values.
What interviewers tend to look for
- Core JavaScript: prototypes, modules, events and
this. - The web platform itself, including the ideas behind web components.
- Accessibility in every component you describe.
- Security, since the products hold customer data.
Your Salesforce 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
6 questions- Question 1 of 15JavaScript
Salesforce 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 2 of 15JavaScript
Salesforce 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 3 of 15JavaScript
Salesforce 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
Salesforce 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 5 of 15JavaScript
Salesforce interviewer
How do ES modules differ from CommonJS, and why does tree shaking depend on ES modules?
Model answer
ES module
importandexportstatements are static. They sit at the top level and are resolved before any code runs, so a bundler can see exactly which exports are used and drop the rest. That removal is tree shaking.CommonJS
requireis an ordinary function call. It can run inside anif, with a computed path, and it returns a plain object, so the bundler cannot be sure what is unused.Other differences: ES module imports are live bindings to the exported variable, ES modules load asynchronously and support top-level
await, and they always run in strict mode.Tree shaking also needs the library to be side-effect free, which packages declare with
"sideEffects": falseinpackage.json. Dynamicimport()is the tool for code splitting: it returns a promise and creates a separate chunk. - Question 6 of 15JavaScript
Salesforce interviewer
What is the difference between a shallow and a deep copy? How would you deep clone an object?
Model answer
A shallow copy (
{ ...obj },Object.assign,arr.slice()) copies one level. Nested objects are still shared with the original.structuredClone(value)is the built-in deep clone. It handles dates, maps, sets, typed arrays and circular references. It throws on functions and DOM nodes and does not keep the prototype chain.JSON.parse(JSON.stringify(value))is weaker: it dropsundefinedand functions, turns dates into strings and fails on cycles.Interviewers usually want it written by hand:
function deepClone(value, seen = new WeakMap()) { if (value === null || typeof value !== 'object') return value; if (seen.has(value)) return seen.get(value); // circular reference const copy = Array.isArray(value) ? [] : {}; seen.set(value, copy); for (const key of Reflect.ownKeys(value)) { copy[key] = deepClone(value[key], seen); } return copy; }Say what it does not cover (Date, Map, Set, class instances) and how you would add each one.
TypeScript
2 questions- Question 7 of 15TypeScript
Salesforce interviewer
Explain any, unknown and never.
Model answer
anyswitches type checking off for a value, and it spreads: anything derived from it is alsoany.unknownalso accepts any value, but you cannot use it until you narrow it. It is the right type for parsed JSON, a caught error and anything from outside your program.neveris the type with no values. A function that always throws returnsnever, and a union that has been fully narrowed isnever. That gives you an exhaustiveness check:type Shape = { kind: 'circle'; r: number } | { kind: 'square'; side: number }; function area(shape: Shape): number { switch (shape.kind) { case 'circle': return Math.PI * shape.r ** 2; case 'square': return shape.side ** 2; default: { // Add a new Shape and forget a case: this line stops compiling. const unreachable: never = shape; throw new Error('Unhandled shape: ' + JSON.stringify(unreachable)); } } } - Question 8 of 15TypeScript
Salesforce interviewer
What does it mean that TypeScript is structurally typed?
Model answer
TypeScript compares types by their shape, not by their name. A value is assignable to a type if it has at least the required properties with compatible types.
interface Point { x: number; y: number; } const marker = { x: 1, y: 2, label: 'home' }; const point: Point = marker; // fine: it has x and y const direct: Point = { x: 1, y: 2, label: 'home' }; // errorThe second assignment fails because of excess property checking, a special rule for object literals written directly where a type is expected. It exists to catch typos.
One consequence: two types with the same shape are interchangeable, so a
UserIdand anOrderIdthat are bothstringcan be mixed up. Branded types fix that:type UserId = string & { readonly __brand: 'UserId' }; type OrderId = string & { readonly __brand: 'OrderId' };
React
1 question- Question 9 of 15React
Salesforce interviewer
What is useRef for? How do you pass a ref to a child component?
Model answer
useRefreturns an object with acurrentproperty that stays the same between renders. Changingcurrentdoes not cause a re-render. Two uses:- Reaching a DOM node, to focus it, measure it or scroll to it.
- Keeping a value that should survive renders but is not shown: a timer id, the previous value of a prop, the latest version of a callback.
Do not read or write
currentwhile rendering. Use it in effects and event handlers.function TextField({ ref, ...props }) { return <input ref={ref} {...props} />; } function Form() { const inputRef = useRef(null); return ( <> <TextField ref={inputRef} /> <button onClick={() => inputRef.current?.focus()}>Edit</button> </> ); }In React 19,
refis an ordinary prop on function components, as above. In React 18 and earlier the child has to be wrapped inforwardRef.useImperativeHandlelets a component expose a small API, such asopen()andclose(), instead of its DOM node.
CSS
2 questions- Question 10 of 15CSS
Salesforce interviewer
What are CSS custom properties, and how would you build a dark theme with them?
Model answer
A custom property is a value you name with two dashes and read with
var(). Unlike a Sass variable, it exists at runtime: it cascades, it is inherited, and it can be changed by a class, a media query or JavaScript without rebuilding anything.:root { --bg: #ffffff; --text: #0f172a; --accent: #4f46e5; } [data-theme='dark'] { --bg: #0b1020; --text: #e2e8f0; --accent: #818cf8; } body { background: var(--bg); color: var(--text); }Components only use the variables, so switching the theme means changing one attribute on the root element.
- Default to the system setting with
@media (prefers-color-scheme: dark)and let the user override it. - Save the choice, and apply it with a small inline script in the head before the page paints. Otherwise the wrong theme flashes on load.
- Set
color-scheme: light darkso that form controls and scrollbars match. var(--gap, 8px)takes a fallback, andelement.style.setProperty('--x', value)sets one from JavaScript.
- Default to the system setting with
- Question 11 of 15CSS
Salesforce interviewer
What is the difference between a pseudo-class and a pseudo-element?
Model answer
A pseudo-class, written with one colon, selects an element in a particular state or position:
:hover,:focus-visible,:disabled,:checked,:first-child,:nth-child(2n),:not(.active).A pseudo-element, written with two colons, styles a part of an element or a box that is not in the HTML:
::before,::after,::placeholder,::selection,::marker,::first-line./* Pseudo-class: a state */ .field:focus-visible { outline: 2px solid var(--accent); } /* Pseudo-element: a generated box. It needs content. */ .required::after { content: ' *'; color: crimson; } /* :has() selects a parent by what it contains */ .card:has(img) { padding-top: 0; }Two that are worth knowing well:
:focus-visibleshows a focus ring for keyboard users without showing it on every mouse click, and:has()lets a parent or an earlier sibling be styled by what follows it, which used to need JavaScript.
Browser, performance and system design
3 questions- Question 12 of 15Browser, performance and system design
Salesforce interviewer
How do you make a web page accessible?
Model answer
- Use the right HTML element. A
buttonis focusable, works with Enter and Space and is announced as a button. Adivwith a click handler does none of that. The same goes fornav,main, headings in order, and alabelfor every input. - Keyboard. Everything must be reachable and usable without a mouse, in a sensible order, with a visible focus ring. When a dialog opens, move focus into it, keep it there, and return it to the trigger on close.
- Text alternatives. Images need
alttext, or an emptyaltif they are decorative. Icon-only buttons need an accessible name. - Colour. Body text needs a contrast ratio of at least 4.5 to 1, and colour should never be the only signal.
- ARIA, when HTML is not enough.
aria-expandedon a toggle,aria-livefor updates that appear without a page load, roles for custom widgets. No ARIA is better than wrong ARIA. - Motion and zoom. Respect
prefers-reduced-motion, and make sure the page works at 200% zoom.
For testing: use the page with the keyboard only, run an automated checker such as axe or Lighthouse, and try a screen reader on the main flows. Automated tools catch only part of the problems.
- Use the right HTML element. A
- Question 13 of 15Browser, performance and system design
Salesforce interviewer
What are XSS and CSRF, and how do you prevent them?
Model answer
XSS (cross-site scripting): an attacker gets their script to run in your page, with your user's access. It can be stored (saved in a comment and shown to others), reflected (bounced back from a URL parameter) or DOM-based (your own JavaScript writes untrusted text into the page).
- Escape everything you render. React does this by default;
dangerouslySetInnerHTMLandinnerHTMLare the holes. - When you have to render user-supplied HTML, sanitise it with a library such as DOMPurify.
- Add a Content Security Policy that blocks inline scripts and unknown sources.
- Keep session cookies
HttpOnlyto limit the damage. - Do not put user input into
hreforsrcwithout checking the scheme, becausejavascript:URLs execute.
CSRF (cross-site request forgery): another site makes the user's browser send a request to yours, and the browser attaches their cookies.
- Set
SameSiteon cookies. - Require a CSRF token, or check the
Originheader, on requests that change data. - Never change data in response to a GET.
Also worth a sentence:
frame-ancestorsin the CSP stops clickjacking, and anything in the frontend bundle is public, so API secrets cannot live there. - Escape everything you render. React does this by default;
- Question 14 of 15Browser, performance and system design
Salesforce interviewer
What is CORS, and what is a preflight request?
Model answer
Browsers enforce the same-origin policy: a script on one origin (scheme, host and port) cannot read a response from another. CORS is how a server opts in to being read by other origins, with response headers such as
Access-Control-Allow-Origin.Simple requests, such as a plain GET or a form-style POST, are sent directly, and the browser hides the response if the header is missing.
Other requests are preflighted. That includes any with a JSON content type, a custom header such as
Authorization, or a method such as PUT or DELETE. The browser first sends anOPTIONSrequest asking whether the real one is allowed:OPTIONS /api/orders Origin: https://app.example.com Access-Control-Request-Method: PUT Access-Control-Request-Headers: content-type, authorization HTTP/1.1 204 No Content Access-Control-Allow-Origin: https://app.example.com Access-Control-Allow-Methods: GET, PUT Access-Control-Allow-Headers: content-type, authorization Access-Control-Max-Age: 600- To send cookies, the request needs
credentials: 'include', and the server must answer withAccess-Control-Allow-Credentials: trueand a specific origin. A wildcard is not allowed with credentials. - CORS is enforced by browsers only. It does not protect an API from other clients.
- A CORS error is fixed on the server, or by proxying through your own origin. Nothing in the frontend code can bypass it.
- To send cookies, the request needs
Machine coding
1 question- Question 15 of 15Machine coding
Salesforce interviewer
Build an accordion, or a tabs component.
Model answer
Accordion. The state is which panel ids are open: one id for a single-open accordion, a set for multi-open. Each header is a real
button.function Accordion({ items, allowMultiple = false }) { const [openIds, setOpenIds] = useState(new Set()); const toggle = (id) => setOpenIds((current) => { const next = new Set(allowMultiple ? current : []); if (current.has(id)) next.delete(id); else next.add(id); return next; }); return items.map((item) => ( <section key={item.id}> <h3> <button aria-expanded={openIds.has(item.id)} aria-controls={'panel-' + item.id} onClick={() => toggle(item.id)} > {item.title} </button> </h3> <div id={'panel-' + item.id} hidden={!openIds.has(item.id)}> {item.content} </div> </section> )); }Tabs. The state is the active tab id. Use
role="tablist",role="tab"witharia-selected, androle="tabpanel". Left and right arrows move between tabs, and only the active tab is in the Tab order (tabIndex0 for it, -1 for the rest).Follow-ups: animate the panel height, make the component controllable from outside, and expose a compound API (
Tabs,Tabs.List,Tabs.Panel).
Practise for Salesforce
Reading answers is the easy half. These problems run in the browser against real tests.
