This guide provides direct, actionable answers to common front-end developer interview questions. You can use these clear, concise explanations to show your understanding and ace your next interview. It covers essential questions and answers for all levels—freshers, intermediate, and advanced.
Ready to Master Front-End Development?
Explore our Frontend Web Development Essentials Course and boost your skills in HTML, CSS, JavaScript, and more!
Explore NowWhat is the difference between div and span tags in HTML?
A div is a block-level element. It takes up the full width available and starts on a new line. Use it for major sections of content. A span is an inline element. It only takes up as much width as its content and does not start a new line. Use it for small pieces of text within a larger block.
Example:
HTML
<div>This is a block-level div.</div>
<span>This is an inline span.</span> Some text after the span.
What are some different ways to center an element horizontally and vertically using CSS, and what are the pros and cons of each method?
You can center elements using Flexbox, Grid, or position: absolute.
Flexbox:
How: Apply display: flex; justify-content: center; align-items: center; to the parent.
Pros: Flexible, responsive, good for single-axis or dual-axis centering.
Cons: Overkill for simple horizontal centering.
CSS
.container-flex {
display: flex;
justify-content: center; /* Horizontal */
align-items: center; /* Vertical */
height: 200px; /* Example height */
}
CSS Grid:
How: Apply display: grid; place-items: center; to the parent.
Pros: Very concise for perfect centering, powerful for complex layouts.
Cons: Newer, not needed for basic layouts.
CSS
.container-grid {
display: grid;
place-items: center; /* Centers both horizontally and vertically */
height: 200px; /* Example height */
}
Position Absolute with Transform:
How: Position the element with position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);.
Pros: Good for overlaying elements, works in older browsers.
Cons: Removes element from document flow, can cause overlap with other elements.
CSS
.centered-absolute {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
What is the box model in CSS?
The CSS box model describes how HTML elements are rendered as boxes. Each box has content, padding, border, and margin.
Content: The actual content of the element (e.g., text, image).
Padding: Space between the content and the border.
Border: A line around the padding and content.
Margin: Space outside the border, separating elements.
The total width/height of an element includes its content, padding, and border. Margin adds space around the element but does not affect its size.
Example:
CSS
.box {
width: 100px;
height: 50px;
padding: 10px; /* Adds 10px inside the border */
border: 2px solid black; /* 2px border */
margin: 15px; /* Adds 15px outside the border */
}/* Total width = 100px (content) + 2*10px (padding) + 2*2px (border) = 124px */
How would you explain the concept of variable declaration in JavaScript to a beginner, including the differences between let, const, and var?
Variables are like containers for storing data. You give them a name, and then you can put values inside.
var: This is the oldest way. var variables can be re-declared and updated. They have function scope, meaning they are available throughout the function they are declared in.
JavaScript
var x = 10;
var x = 20; // Re-declared, no error
console.log(x); // 20
let: Introduced in ES6. let variables can be updated but not re-declared in the same scope. They have block scope, meaning they are limited to the block (e.g., inside {}) where they are defined.
JavaScript
let y = 10;
y = 20; // Updated
// let y = 30; // Error: Cannot re-declare
if (true) {
let z = 5;
}
// console.log(z); // Error: z is not defined (out of scope)
const: Also introduced in ES6. const variables cannot be re-declared or updated after their initial assignment. They also have block scope. You must assign a value when you declare a const variable.
JavaScript
const PI = 3.14;
// PI = 3.14159; // Error: Cannot update
// const G; // Error: Missing initializer
Use const by default. If you need to reassign the variable later, use let. Avoid var in modern JavaScript.
How do you select an element with a specific ID in CSS?
You select an element by its ID using the hash symbol (#) followed by the ID name.
Example:
CSS
#myElement {
color: blue;
font-size: 18px;
}
In HTML, you would have:
HTML
<p id="myElement">This text will be blue and 18px.</p>
A potential pitfall is that IDs must be unique within an HTML document. Using the same ID multiple times will lead to invalid HTML and unpredictable styling.
What is the purpose of the alt attribute in an img tag?
The alt attribute provides alternative text for an image.
Accessibility: Screen readers use alt text to describe the image to visually impaired users. This helps them understand the content.
SEO: Search engines use alt text to understand the image content. This improves image search ranking.
Fallback: If the image fails to load, the alt text is displayed instead.
Example:
HTML
<img src="flower.jpg" alt="A red rose in full bloom" />
How do you create a flexbox container in CSS?
To create a flexbox container, set the display property of a parent element to flex or inline-flex.
display: flex; Creates a block-level flex container.
display: inline-flex; Creates an inline-level flex container.
Once the parent is a flex container, its direct children become flex items. You can then use flex properties to control their layout.
Example:
CSS
.flex-container {
display: flex; /* Makes this element a flex container */
justify-content: space-between; /* Distributes space between items */
align-items: center; /* Aligns items vertically in the center */
}
HTML
<div class="flex-container">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>
What is the difference between == and === in JavaScript?
== (loose equality): Compares two values after converting them to a common type. It checks for value equality, not type.
JavaScript
console.log(5 == "5"); // true (string "5" is converted to number 5)
console.log(0 == false); // true (false is converted to 0)
=== (strict equality): Compares two values without type conversion. It checks for both value and type equality.
JavaScript
console.log(5 === "5"); // false (number vs. string)
console.log(0 === false); // false (number vs. boolean)
Always use === unless you have a specific reason to use ==. === is more predictable and avoids unexpected type coercion issues.
How do you add an event listener to an element in JavaScript?
You use the addEventListener() method on an HTML element.
Example:
JavaScript
const myButton = document.getElementById('myButton');
// Add a click event listener
myButton.addEventListener('click', function() {
console.log('Button clicked!');
});
The first argument is the event type (e.g., ‘click’, ‘mouseover’, ‘submit’).
The second argument is the function to execute when the event occurs (the event handler).
Event Propagation: Events can propagate through the DOM. This involves two phases:
Capturing phase: The event travels from the window down to the target element.
Bubbling phase: The event bubbles up from the target element back to the window.
Most addEventListener calls default to the bubbling phase. You can control this with an optional third argument.
What is the purpose of the DOCTYPE declaration in HTML?
The <!DOCTYPE html> declaration tells the web browser which HTML version the document uses.
Rendering: It ensures the browser renders the page in “standards mode” rather than “quirks mode.” Standards mode follows modern web standards, providing consistent rendering across browsers. Quirks mode emulates older browser bugs, which can lead to layout issues.
Standards Compliance: It signals the document’s adherence to the HTML5 specification.
You place it at the very beginning of your HTML document, before the <html> tag.
Example:
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>My Page</title>
</head>
<body>
<h1>Hello</h1>
</body>
</html>
What is the difference between inline and block elements in HTML?
Block-level elements:
Start on a new line.
Take up the full available width.
Examples: <div>, <p>, <h1>, <ul>, <form>.
HTML
<p>This is a paragraph.</p>
<div>This is a div.</div>
Inline elements:
Do not start on a new line.
Only take up as much width as their content.
Examples: <span>, <a>, <img>, <strong>, <em>.
HTML
This is <span>inline text</span> within a sentence.
<a href="#">Click me</a>.
You can change an element’s display type using the CSS display property.
How do you create a hyperlink in HTML?
You create a hyperlink using the <a> (anchor) tag.
The href attribute specifies the destination URL (the address you want to link to).
The text between the opening and closing <a> tags is the clickable text.
Example:
HTML
<a href="https://www.example.com">Visit Example Website</a>
To link to another page within the same website:
HTML
<a href="/about.html">About Us</a>
What is the purpose of the title attribute in HTML?
The title attribute provides advisory information about an element.
Tooltips: When a user hovers over the element, the title text often appears as a tooltip.
Accessibility: It can provide additional context for screen readers, though alt for images and proper semantic HTML are usually more crucial.
SEO: Less impactful than alt for images, but can offer minor context to search engines for some elements.
Example:
HTML
<p title="This is a paragraph about web development.">
Hover over this text to see the tooltip.</p>
<a href="https://www.google.com" title="Search the web with Google">
Google</a>
How do you style an element with a specific class in CSS?
You style an element with a class using a dot (.) followed by the class name.
Example:
CSS
.my-class {
color: green;
font-weight: bold;
}
In HTML, you would apply the class to your element:
HTML
<span class="my-class">This text will be green and bold.</span>
<div class="my-class">This div also uses the same style.</div>
You can apply the same class to multiple elements. An element can also have multiple classes.
What is the difference between getElementById and querySelector in JavaScript?
Both methods select HTML elements, but they differ in flexibility and how they select.
document.getElementById():
Selects a single element by its id attribute.
Returns the element object or null if not found.
Is generally faster for ID lookups.
JavaScript
const myDiv = document.getElementById('myUniqueDiv');
// <div id="myUniqueDiv"></div>
document.querySelector():
Selects the first element that matches a specified CSS selector.
Returns the element object or null if no match.
Offers more flexibility as it uses CSS selectors (e.g., class, tag, attribute selectors).
JavaScript
const firstParagraph = document.querySelector('p'); // First <p>
const specificClass = document.querySelector('.my-class'); // First element with class "my-class"
Use getElementById for quick, direct ID lookups. Use querySelector for more complex or general selections based on CSS rules. If you need to select multiple elements, use querySelectorAll.
How do you create a function in JavaScript?
You create a function using the function keyword, followed by a name, parentheses for parameters, and curly braces for the code block.
Example:
JavaScript
// Function Declaration
function greet(name) {
console.log("Hello, " + name + "!");
}
// Call the function
greet("Alice"); // Output: Hello, Alice!
name: A placeholder for data the function will work with.
parameters: Values passed into the function when it’s called.
You can also use function expressions or arrow functions.
JavaScript
// Function Expression
const add = function(a, b) {
return a + b;
};
console.log(add(5, 3)); // Output: 8
// Arrow Function
const multiply = (x, y) => x * y;
console.log(multiply(4, 2)); // Output: 8
What is the purpose of the return statement in JavaScript?
The return statement exits a function and sends a value back to where the function was called.
Exit: When return is encountered, the function stops executing.
Value Passing: It specifies the value that the function will “give back.” If no return statement is present, or if return; is used without a value, the function returns undefined.
Example:
JavaScript
function calculateArea(width, height) {
const area = width * height;
return area; // Sends the calculated area back
}
let result = calculateArea(10, 5);
console.log(result); // Output: 50
How do you loop through an array in JavaScript?
You can loop through an array using several methods.
1. for loop:
JavaScript
const fruits = ["apple", "banana", "cherry"];
for (let i = 0; i < fruits.length; i++) {
console.log(fruits[i]);
}
// Output: apple, banana, cherry (each on a new line)
2. forEach method:
JavaScript
const colors = ["red", "green", "blue"];
colors.forEach(function(color) {
console.log(color);
});
// Output: red, green, blue (each on a new line)
3. for...of loop (ES6):
JavaScript
const numbers = [1, 2, 3];
for (const num of numbers) {
console.log(num);
}
// Output: 1, 2, 3 (each on a new line)
forEach is often preferred for simple iteration. for loops offer more control, like breaking or continuing the loop. for...of is clean for iterating directly over values.
What is the difference between for and while loops in JavaScript?
Both for and while loops repeat a block of code, but they differ in structure and typical use cases.
for loop:
Best for when you know how many times you want to loop (or can determine it easily).
It has a clear initialization, condition, and increment/decrement step in its syntax.
JavaScript
for (let i = 0; i < 5; i++) {
console.log(i); // 0, 1, 2, 3, 4
}
while loop:
Best for when the number of iterations is unknown and depends on a condition.
The condition is checked before each iteration. The loop continues as long as the condition is true.
JavaScript
let count = 0;
while (count < 3) {
console.log(count); // 0, 1, 2
count++;
}
Use for when you iterate over a known range or collection. Use while when you need to loop until a certain condition is met.
How do you add a comment in HTML, CSS, and JavaScript?
Comments are notes in your code that browsers and interpreters ignore. They help explain your code.
HTML Comments:
HTML
<!-- This is an HTML comment -->
<p>Hello World</p>
CSS Comments:
CSS
/* This is a single-line CSS comment */
p {
color: blue; /* This comments on the color property */
}
/*
* This is a multi-line
* CSS comment
*/
JavaScript Comments:
JavaScript
// This is a single-line JavaScript comment
/*
* This is a multi-line
* JavaScript comment
*/
let x = 10; // This comments on the variable declaration
What is the purpose of ARIA attributes in HTML?
ARIA (Accessible Rich Internet Applications) attributes enhance the accessibility of web content. They provide additional semantic information to assistive technologies like screen readers.
Role: Defines the general type of UI widget (e.g., role="button", role="navigation").
States: Describes the current condition of an element (e.g., aria-expanded="true" for an open menu).
Properties: Provides essential characteristics (e.g., aria-label="Close button" for a button with no visible text).
ARIA does not change the visual appearance or behavior of elements. It only affects how assistive technologies interpret them.
Example:
HTML
<button aria-label="Close dialog" role="button">X</button>
<div role="alert" aria-live="polite">New message received!</div>
How do you make an image accessible to screen readers?
Making images accessible involves providing text alternatives.
alt attribute: This is the primary way. Provide a concise, descriptive text that conveys the image's content and purpose.
HTML
<img src="mountain.jpg" alt="A serene landscape with snow-capped mountains and a clear blue lake" />
Decorative images: If an image is purely decorative and adds no information (e.g., a background pattern), set alt="" (an empty alt attribute). This tells screen readers to ignore it.
HTML
<img src="spacer.gif" alt="" />
Context: Ensure images are placed within meaningful HTML structures. If an image is part of a complex graphic (e.g., a chart), provide a text summary nearby or link to a detailed description.
What is the difference between semantic and non-semantic HTML elements?
Semantic HTML elements:
Convey meaning about their content and purpose.
Help browsers, search engines, and assistive technologies understand the page structure.
Examples: <header>, <nav>, <main>, <article>, <section>, <footer>.
HTML
<header><h1>Website Title</h1></header>
<nav><ul><li><a href="#">Home</a></li></ul></nav>
<article><p>Article content.</p></article>
Non-semantic HTML elements:
Do not convey any inherent meaning about their content.
Used purely for styling or grouping content where no specific semantic element applies.
Examples: <div>, <span>.
HTML
<div class="container">
<span class="highlight">Important</span> text.</div>
Using semantic HTML improves accessibility, SEO, and code maintainability.
What is the purpose of Git?
Git is a distributed version control system. It tracks changes in source code during software development.
Version Control: Git allows you to record changes to files over time. You can revert to previous versions, compare changes, and see who made what changes.
Collaboration: Multiple developers can work on the same project simultaneously. Git helps manage and merge their changes without conflicts.
Backup: Your entire project history is stored, acting as a robust backup.
It's essential for team development and managing project evolution.
How do you create a new branch in Git?
You create a new branch in Git using the git branch command, followed by the branch name.
Example:
Bash
git branch new-feature
This command creates the branch but does not switch to it. To switch to the new branch, use git checkout.
Bash
git checkout new-feature
You can combine these steps into one command using git checkout -b.
Bash
git checkout -b another-feature
Branches allow you to work on new features or bug fixes in isolation without affecting the main codebase.
What is the difference between git merge and git rebase?
Both git merge and git rebase integrate changes from one branch into another, but they do it differently.
git merge:
Combines the histories of two branches.
Creates a new "merge commit" that has two parent commits.
Preserves the original commit history, showing exactly when branches were merged.
Bash
# On main branch
git merge feature-branch
git rebase:
Moves or re-applies a series of commits from one branch onto another.
Rewrites the commit history to create a linear history. It looks like development happened sequentially.
Can make the commit history cleaner but can be risky if you rebase branches that have already been pushed to a shared remote repository.
Bash
# On feature-branch
git rebase main
Use git merge to maintain an accurate, non-rewritten history. Use git rebase for a cleaner, linear history, especially for local feature branches before merging them into main. Avoid rebasing commits that others have already pulled.
What is the purpose of the lang attribute in HTML?
The lang attribute specifies the human language of the element's content.
Accessibility: Screen readers and other assistive technologies use it to pronounce text correctly. For example, lang="es" tells a screen reader to use a Spanish voice.
Search Engines: Helps search engines understand the language of the content, which can improve search results for language-specific queries.
Browser Behavior: Can influence how browsers handle text, such as hyphenation or font selection.
You typically place it on the <html> tag to declare the default language for the entire page.
HTML
<html lang="en">
</html>
You can also use it on specific elements if parts of your content are in a different language.
HTML
<p>
Hello. This is an English paragraph.
<span lang="es">Hola. Este es un párrafo en español.</span>
</p>
How do you create a list in HTML?
You create lists in HTML using unordered lists (<ul>) and ordered lists (<ol>), with list items (<li>) inside them.
Unordered List (<ul>):
Used for items where the order doesn't matter (e.g., a list of features).
Items are typically marked with bullet points.
HTML
<ul>
<li>Milk</li>
<li>Bread</li>
<li>Eggs</li>
</ul>
Ordered List (<ol>):
Used for items where the order is important (e.g., steps in a recipe, a ranking).
Items are typically marked with numbers.
HTML
<ol>
<li>First step</li>
<li>Second step</li>
<li>Third step</li>
</ol>
You place each individual item inside an <li> tag.
How do you implement a responsive design using media queries?
You use CSS media queries to apply styles based on device characteristics. This allows your layout to adapt to different screen sizes.
Example adjusting layout based on screen size:
CSS
/* Base styles */
.container {
width: 100%;
}
/* For screens under 768px */
@media (max-width: 767px) {
.container {
padding: 15px;
}
}
/* For screens over 768px */
@media (min-width: 768px) {
.container {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
}
}
This code changes the .container layout. It uses padding below 768px. It becomes a two-column grid above 768px.
What are CSS preprocessors, and why would you use one?
CSS preprocessors extend CSS with features like variables and nesting. You use them to write more maintainable and efficient CSS. Tools like Sass compile this code into standard CSS.
Discuss tools like Sass or Less and their benefits (e.g., variables, nesting):
Sass and Less offer several benefits:
- Variables: Define reusable values. Example:
$primary-color: #336699;
. - Nesting: Nest CSS selectors. This matches HTML structure.
- Mixins: Create reusable CSS blocks.
These features make large stylesheets easier to manage.
Explain the concept of closures in JavaScript.
A closure is a function that remembers its outer environment. It accesses variables from its containing scope. This happens even after that scope closes.
Use an example to show how variables are retained in scope:
JavaScript
function makeGreeter(greeting) {
return function(name) {
console.log(greeting + ', ' + name);
};
}
const greetHello = makeGreeter('Hello');
greetHello('Alice'); // Shows: Hello, Alice
The greetHello function remembers greeting from makeGreeter.
How do you optimize the loading time of a web page?
You optimize web page loading time using various techniques. This improves user experience.
Suggest techniques like minification, image compression, or lazy loading:
- Minification: Remove extra characters from code. Use tools like Terser.
- Image Compression: Reduce image file sizes. Use tools like TinyPNG.
- Lazy Loading: Load images or videos only when visible. Add
loading="lazy"
to<img>
tags. - Code Splitting: Break large JavaScript bundles into smaller parts.
- Caching: Store static assets in the browser.
What is the difference between localStorage and sessionStorage?
Both localStorage and sessionStorage store data in the browser. They differ in how long data lasts and its reach.
Compare their persistence and scope:
localStorage
: Data persists after the browser closes. It has no expiration. Its scope is per domain.sessionStorage
: Data clears when the browser tab closes. Its scope is per tab.
How do you handle cross-browser compatibility issues?
You handle cross-browser issues by testing across different browsers. You also use specific tools and techniques.
Describe tools (e.g., caniuse) and techniques (e.g., vendor prefixes):
Tools:
- caniuse.com: Check browser support for features.
- BrowserStack: Perform testing on various browsers.
Techniques:
- Vendor Prefixes: Use prefixes like
-webkit-
for experimental CSS. Example:-webkit-flex
. - Autoprefixer: This tool adds vendor prefixes automatically.
- Feature Detection: Use JavaScript to check for browser support.
- Polyfills: Provide modern functionality for older browsers.
What is the purpose of a CSS reset?
A CSS reset normalizes default styles across different browsers. Browsers apply their own base styling. These defaults vary.
Explain how it normalizes default styles across browsers:
A CSS reset applies a consistent baseline. It often sets margins and paddings to zero. This ensures your design looks the same in different browsers. Popular resets include Normalize.css.
Explain the concept of promises in JavaScript.
A Promise is an object. It represents the eventual success or failure of an async operation. It helps manage async code.
Provide an example of handling asynchronous operations:
JavaScript
const fetchData = new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve('Data fetched.');
} else {
reject('Error occurred.');
}
}, 1000);
});
fetchData
.then(message => {
console.log(message); // On success
})
.catch(error => {
console.error(error); // On failure
});
This code uses a Promise to handle a delayed data fetch.
How do you use async and await in JavaScript?
async
and await
are syntax features built on Promises. They make async code look like sync code. This improves readability.
Show how they simplify promise-based code:
JavaScript
async function getData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Fetch failed:', error);
}
}
getData();
await
pauses execution until the Promise resolves. async
functions always return a Promise.
What is the difference between margin and padding in CSS?
Both margin and padding create space around elements. They affect layout and spacing differently.
Contrast their effect on layout and spacing:
padding
: Creates space inside an element. It is between content and its border. It adds to the element's size.margin
: Creates space outside an element. It is between its border and other elements. Margins can collapse.
How do you implement a grid layout in CSS?
You implement a grid layout using CSS Grid. This creates two-dimensional layouts with rows and columns.
Demonstrate a basic grid setup with columns and rows:
HTML
<div class="grid-container">
<div class="grid-item">1</div>
<div class="grid-item">2</div>
</div>
CSS
.grid-container {
display: grid;
grid-template-columns: 1fr 1fr; /* Two equal columns */
grid-template-rows: auto auto; /* Rows size based on content */
gap: 10px; /* Space between items */
}
.grid-item {
background-color: lightblue;
padding: 20px;
}
This sets up a two-column grid with automatic rows.
What is the purpose of the z-index property in CSS?
The z-index
property controls the stacking order of positioned elements. Higher z-index
values appear in front.
Explain how it controls stacking order:
z-index
works only on elements with position
set. This includes absolute
, relative
, fixed
, or sticky
. It determines which element overlaps another.
How do you create a transition effect in CSS?
You create transition effects using the transition
property. This makes property changes occur smoothly.
Provide an example animating a property like opacity:
CSS
.box {
opacity: 1;
transition: opacity 0.5s ease-in-out; /* 0.5s transition */
}
.box:hover {
opacity: 0.5; /* Change on hover */
}
Hovering over .box
smoothly changes its opacity.
What is the difference between position: relative and position: absolute in CSS?
Both position: relative
and position: absolute
change element positioning. They differ in how they relate to the document flow.
Compare their positioning behavior relative to parents or the viewport:
position: relative
: Positions the element relative to its normal spot. Offsets move it. It creates a positioning context for absolute children.position: absolute
: Removes the element from document flow. It positions relative to its nearest positioned ancestor. If no positioned ancestor exists, it uses the viewport.
How do you handle form validation in JavaScript?
You handle form validation in JavaScript by checking user input. This ensures data is correct before submission.
Show a simple example checking input values:
HTML
<form id="myForm">
<input type="text" id="username" required>
<button type="submit">Submit</button>
</form>
<script>
document.getElementById('myForm').addEventListener('submit', function(event) {
const usernameInput = document.getElementById('username');
if (usernameInput.value.trim() === '') {
alert('Username empty.');
event.preventDefault(); // Stop submission
}
});
</script>
This script stops submission if the username is empty.
What is the purpose of the Fetch API in JavaScript?
The Fetch API provides an interface for network requests. It is a modern way to retrieve resources asynchronously.
Explain how it retrieves resources asynchronously:
The Fetch API uses Promises. You call fetch()
. This returns a Promise. The Promise resolves to a Response object. You use .then()
to process the response data.
JavaScript
fetch('https://api.example.com/users')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
This code fetches user data from an API.
What is the difference between map, filter, and reduce in JavaScript?
map
, filter
, and reduce
are array methods. They iterate over arrays. They serve different purposes in transforming data.
Compare their purposes with examples transforming an array:
map()
: Creates a new array. It calls a function on each element.
JavaScript
const numbers = [1, 2, 3];
const doubled = numbers.map(num => num * 2); // doubled is [2, 4, 6]
filter()
: Creates a new array. It includes only elements that pass a test.
JavaScript
const numbers = [1, 2, 3, 4];
const evens = numbers.filter(num => num % 2 === 0); // evens is [2, 4]
reduce()
: Processes each element. It returns a single value.
JavaScript
const numbers = [1, 2, 3];
const sum = numbers.reduce((acc, current) => acc + current, 0); // sum is 6
How do you create a module in JavaScript?
You create modules using export
and import
. This organizes code into reusable files.
Demonstrate using export and import:
utils.js
:
JavaScript
export function add(a, b) {
return a + b;
}
export const PI = 3.14;
main.js
:
JavaScript
import { add, PI } from './utils.js';
console.log(add(5, 3)); // 8
console.log(PI); // 3.14
This makes add
and PI
available for use.
What is the purpose of the export and import statements in JavaScript?
export
and import
statements enable modular code. They break large applications into smaller files.
Explain how they enable modular code:
export
: Marks values for use in other files. It makes code public.import
: Brings exported values into the current file. This allows code reuse.
This system improves code organization and maintenance.
How do you ensure that a web page is accessible to users with disabilities?
You ensure web page accessibility by following best practices. This makes content usable for all.
Suggest practices like semantic HTML and keyboard support:
- Semantic HTML: Use HTML tags based on meaning. Use
<nav>
for navigation. This helps screen readers. - Keyboard Support: Ensure elements are reachable by keyboard. Users should tab through links.
- ARIA Attributes: Use WAI-ARIA for complex elements. Example:
aria-label
. - Alt Text: Provide descriptive
alt
for images. - Color Contrast: Ensure good text-background contrast.
What is the purpose of the tabindex attribute in HTML?
The tabindex
attribute controls an element's tab order. It determines if an element is focusable.
Discuss how it controls focus order:
tabindex="0"
: Element is focusable. Its order is based on document position.tabindex="-1"
: Element is focusable by script, but not by Tab key.tabindex="positive number"
: Element is focusable. Lower numbers are tabbed first. Avoid using positive values.
How do you implement keyboard navigation in a web application?
You implement keyboard navigation by ensuring all interactive elements are focusable. Users should move between them with the Tab key.
Provide an example ensuring focusable elements are navigable:
- Use native HTML elements like
<button>
,<input>
,<a href="...">
. These are focusable by default. - For custom components, add
tabindex="0"
. - Manage focus for complex elements like modals.
HTML
<nav>
<a href="#home">Home</a>
<button>Click Me</button>
</nav>
These elements are naturally navigable by keyboard.
How do you resolve merge conflicts in Git?
You resolve merge conflicts when changes in two branches overlap. Git flags these conflicts.
Walk through identifying and fixing conflicts manually:
- Identify: Git shows conflicted files. Sections are marked with
<<<<<<<
,=======
,>>>>>>>
. - Fix: Edit the file. Remove Git markers. Keep the desired code.
- Add:
git add <filename>
marks the conflict as resolved. - Commit:
git commit -m "Resolved conflict"
finishes the merge.
What is the purpose of a pull request?
A pull request (PR) is a request to merge changes from one branch to another. It is key for collaborative development.
Explain its role in code review and collaboration:
PRs enable code review. Developers review changes and give feedback. This ensures code quality. It also acts as a discussion forum before changes merge into the main codebase.
How do you squash commits in Git?
You squash commits in Git to combine multiple small commits. This cleans up your commit history.
Provide the commands to combine multiple commits:
- Start rebase:
git rebase -i HEAD~N
(N is number of commits). An editor opens. - Edit instructions: Change
pick
tosquash
(ors
) for commits to combine. Keeppick
for the first commit. - Save and exit: Edit the new combined commit message.
- Save and exit: Commits are squashed.
What is the purpose of unit testing in front-end development?
Unit testing in front-end development verifies individual components or functions. It ensures they work as expected.
Discuss how it ensures component reliability:
Unit tests isolate small code pieces. This helps identify bugs in specific functions. It confirms changes do not break existing features. This builds confidence in your code.
How do you write a unit test for a JavaScript function?
You write a unit test using a testing framework. This framework provides assertions to check function behavior.
Show a simple test case using a framework like Jest:
sum.js
:
JavaScript
export function sum(a, b) {
return a + b;
}
sum.test.js
:
JavaScript
Frontend Developer Interview Questions and Answersimport { sum } from './sum';
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
Run jest
in your terminal to execute this test.
What is the difference between Jest and Mocha testing frameworks?
Jest and Mocha are JavaScript testing frameworks. They help write and run tests. They differ in features.
Compare their features and ecosystems:
Jest:
- Features: An all-in-one solution. It includes a test runner, assertion library, and mocking.
- Ecosystem: Developed by Facebook. Used widely in React projects.
Mocha:
- Features: A more flexible test framework. It is a test runner. It needs separate assertion libraries like Chai.
- Ecosystem: Older and established. Requires more setup but offers more customization.
What is the purpose of a task runner like Gulp or Grunt?
A task runner automates repetitive development tasks. This saves time and ensures consistency.
Explain how it automates build tasks:
Task runners automate tasks like:
- Minification: Compressing CSS and JavaScript.
- Compilation: Converting Sass to CSS.
- Linting: Checking code for errors.
- Image Optimization: Reducing image sizes.
- Live Reloading: Refreshing the browser on code changes.
You configure these tools to run specific tasks.
How do you configure a Webpack build for a React application?
You configure a Webpack build using a webpack.config.js
file. This file tells Webpack how to process your code.
Outline key settings like entry, output, and loaders:
A basic webpack.config.js
includes:
JavaScript
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'],
},
},
},
],
},
};
entry
: The starting point for bundling.output
: Where bundled files go.module.rules
: Configures loaders for file types. (e.g., Babel for React).
How do you implement a sticky header in CSS?
You implement a sticky header using position: sticky
. An element stays in its flow until it reaches a scroll point, then it "sticks" to the viewport.
Demonstrate using position: sticky
:
HTML
<header class="sticky-header">
<h1>My Site</h1>
</header>
<div style="height: 1500px;">Content</div>
CSS
.sticky-header {
position: sticky;
top: 0; /* Sticks to top */
background-color: #f0f0f0;
padding: 10px;
z-index: 1000;
}
The header stays at the top when you scroll past it.
What is the purpose of the data- attribute in HTML?
The data-
attribute stores custom data on HTML elements. This passes data from HTML to JavaScript.
Discuss its use for custom metadata:
You use data-
attributes to:
- Store UI state: Mark elements as "active."
- Pass configuration: Provide settings for components.
Example:
HTML
<button data-product-id="123">Add</button>
<script>
const button = document.querySelector('button');
console.log(button.dataset.productId); // Shows: "123"
</script>
You access data-
attributes using dataset
in JavaScript.
How do you implement a lazy loading mechanism for images?
You implement lazy loading for images using two methods.
First, use the loading="lazy" attribute in your HTML <img> tags. This tells the browser to defer loading the image until it nears the viewport.
HTML
<img src="image.jpg" alt="Description" loading="lazy">
Second, use JavaScript with the Intersection Observer API. This API detects when an image enters the visible area of the browser.
JavaScript
const images = document.querySelectorAll('img[data-src]');
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src; // Loads the image
img.removeAttribute('data-src'); // Removes the data attribute
observer.unobserve(img); // Stops observing
}
});
});
images.forEach(image => {
observer.observe(image); // Starts observing each image
});
This script observes images. When an image becomes visible, its data-src value moves to src, loading the image.
Explain the concept of hoisting in JavaScript.
Hoisting moves declarations to the top of their scope. This happens during the JavaScript compilation phase.
var
declarations are hoisted and initialized to undefined. This means you can access them before their declaration in the code.
JavaScript
console.log(myVar); // Output: undefined
var myVar = 10;
Function declarations are also hoisted. You can call a function before its definition in the code.
JavaScript
myFunction(); // Output: "Hello!"
function myFunction() {
console.log("Hello!");
}
let
and const
declarations are also hoisted. However, they are not initialized. Trying to access them before their declaration results in a ReferenceError. This period is called the "Temporal Dead Zone."
What is the difference between null and undefined in JavaScript?
null
and undefined
both indicate an absence of value. However, their meanings and origins differ.
undefined
means a variable has been declared but has not been assigned any value. It is also the default value for unprovided function parameters.
JavaScript
let myVariable;
console.log(myVariable);
// Output: undefined
null
means a variable has been intentionally assigned "no value." It is a primitive value representing the intentional absence of any object value.
JavaScript
let myValue = null;
console.log(myValue);
// Output: null
How do you handle errors in JavaScript?
You handle errors in JavaScript primarily with try-catch
blocks. These blocks let you catch and manage exceptions thrown during code execution.
JavaScript
try {
// Code that might throw an error
throw new Error("Something went wrong!");
} catch (error) {
console.error("Caught an error:", error.message);
}
You can also create custom error types. Extend the built-in Error
object to define your own error classes.
JavaScript
class CustomError extends Error {
constructor(message) {
super(message);
this.name = "CustomError";
}
}
try {
throw new CustomError("This is a custom error.");
} catch (error) {
console.error(error.name + ": " + error.message);
}
What is the purpose of the this
keyword in JavaScript?
The this
keyword refers to the object that owns the current execution context. Its value is determined by how the function is called.
In a method call, this
refers to the object the method belongs to.
JavaScript
const person = {
name: "Alice",
greet: function() {
console.log("Hello, " + this.name);
}
};
person.greet();
// Output: Hello, Alice
In a standalone function call (non-strict mode), this
refers to the global object (e.g., window
in browsers).
JavaScript
function showThis() {
console.log(this);
}
showThis(); // Output: Window object (in browsers)
With arrow functions, this
does not have its own binding. It inherits the this
value from its enclosing lexical context.
How do you implement a debounce function in JavaScript?
A debounce function is used to limit the rate at which a function is called. It ensures that the function is only executed after a certain amount of time has passed since the last event, like a button click or typing in a text field.
Example of a Debounce Function:
javascript
// Debounce function implementation
function debounce(func, delay) {
let timeout;
return function(...args) {
clearTimeout(timeout); // Clear previous timeout
timeout = setTimeout(() => {
func(...args); // Call the function after the specified delay
}, delay);
};
}
// Example usage:
const log = () => console.log("Debounced!");
const debouncedLog = debounce(log, 1000);
// Wait 1000ms (1 second) before calling log
debouncedLog(); // If called multiple times in quick succession, only one call happens after 1 second
Explanation:
The debounce function waits for the user to stop calling the function (e.g., after typing stops) and then executes it after a delay. If the event happens again before the delay ends, the previous call is canceled, and the timer resets.
What is the difference between call, apply, and bind in JavaScript?
call
, apply
, and bind
are function methods. They all control the this
context for a function.
call()
executes the function immediately. You pass arguments individually.
JavaScript
function greet(greeting) {
console.log(greeting + ", " + this.name);
}
const person = { name: "Bob" };
greet.call(person, "Hi");
// Output: Hi, Bob
apply()
also executes the function immediately. You pass arguments as an array.
JavaScript
function greet(greeting, punctuation) {
console.log(greeting + ", " + this.name + punctuation);
}
const person = { name: "Charlie" };
greet.apply(person, ["Hello", "!"]); // Output: Hello, Charlie!
bind()
does not execute the function immediately. It returns a new function with the this
context permanently set.
JavaScript
function greet() {
console.log("Hello, " + this.name);
}
const person = { name: "David" };
const boundGreet = greet.bind(person);
boundGreet();
// Output: Hello, David
How do you optimize the performance of a React application?
You optimize React application performance using several techniques.
Use memoization for components and expensive computations. React.memo
prevents a functional component from re-rendering if its props have not changed.
JavaScript
const MyComponent = React.memo(function MyComponent(props) {
// Component renders only if props change
return <p>{props.value}</p>;
});
Implement code splitting with React.lazy
and Suspense
. This loads only the necessary code bundles when components are rendered.
JavaScript
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyPage() {
return (
<React.Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</React.Suspense>
);
}
Virtualize large lists using libraries like react-window. This renders only the items visible in the viewport, improving performance for long lists.
What is the purpose of the key
prop in React?
The key
prop in React helps React identify which items in a list have changed, been added, or removed. It provides a stable identity for each component rendered in a list.
React uses keys to optimize list rendering. When a list's order or contents change, keys allow React to efficiently update the UI. It helps React correctly reorder existing elements instead of creating new ones.
JavaScript
<ul>
{items.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
Always use a stable and unique identifier for keys, such as an item's unique ID from a database. Avoid using array indices as keys if the list items can change order.
How do you implement a custom hook in React?
You implement a custom hook in React as a JavaScript function. Its name must start with use
. Custom hooks encapsulate reusable stateful logic.
JavaScript
import { useState, useEffect } from 'react';
function useWindowSize() {
const [size, setSize] = useState({
width: window.innerWidth,
height: window.innerHeight,
});
useEffect(() => {
const handleResize = () => {
setSize({
width: window.innerWidth,
height: window.innerHeight,
});
};
window.addEventListener('resize', handleResize);
// Cleanup function
return () => window.removeEventListener('resize', handleResize);
}, []);
// Empty dependency array means this effect runs once on mount
return size;
}
// How to use it in a component:
function MyComponent() {
const windowSize = useWindowSize();
// Use the custom hook
return (
<p>Window size: {windowSize.width}x{windowSize.height}</p>
);
}
This useWindowSize
hook tracks and provides the current window dimensions. You can use it in any functional component that needs this information.
How do you implement a service worker in a web application?
You implement a service worker to enable features like caching and offline support for your web application. First, register the service worker in your main JavaScript file. This tells the browser about your service worker script.
JavaScript
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('https://d3w1kvgvzbz2b5.cloudfront.net/service-worker.js')
.then(registration => {
console.log('Service Worker registered:', registration);
})
.catch(error => {
console.error('Service Worker registration failed:', error);
});
});
}
Second, create the service-worker.js
file. This file contains the logic for caching and network requests.
JavaScript
// service-worker.js
const CACHE_NAME = 'my-app-cache-v1';
const urlsToCache = [
'/',
'/index.html',
'https://d3w1kvgvzbz2b5.cloudfront.net/styles.css',
'https://d3w1kvgvzbz2b5.cloudfront.net/script.js',
'/images/logo.png'
];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => {
return cache.addAll(urlsToCache);
})
);
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
// Return cached response if found, else fetch from network
return response || fetch(event.request);
})
);
});
This example caches defined URLs during installation and serves them from the cache during fetch requests.
What is the purpose of the useEffect
hook in React?
The useEffect
hook in React lets you perform side effects in functional components. Side effects include data fetching, subscriptions, or manually changing the DOM.
useEffect
runs after every render by default. You can control when it runs using its dependency array.
JavaScript
import { useState, useEffect } from 'react';
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
// This runs after every render
document.title = `You clicked ${count} times`;
// Cleanup function (optional)
return () => {
// Clean up resources if needed
};
}, [count]);
// Effect re-runs only when 'count' changes
return (
<button onClick={() => setCount(count + 1)}>
Click me ({count})
</button>
);
}
In this example, useEffect
updates the document title based on the count state. It only re-runs when count
changes, as specified by the dependency array [count]
.
How do you handle state management in a large React application?
You handle state management in large React applications using various approaches.
The Context API is a built-in React feature. It provides a way to pass data through the component tree without prop drilling. It is suitable for sharing globally accessible data like theme or user authentication status.
JavaScript
// Create Context
const MyContext = React.createContext();
// Provide Context
function MyProvider({ children }) {
const [data, setData] = useState("Hello Context");
return (
<MyContext.Provider value={data}>
{children}
</MyContext.Provider>
);
}
// Consume Context
function MyConsumerComponent() {
const data = useContext(MyContext);
return <p>{data}</p>;
}
Redux is a predictable state container for JavaScript apps. It uses a single, centralized store for the application's state. Redux is good for complex applications with many interacting components and frequent state updates. It enforces a strict data flow.
Other options include Zustand, Jotai, and Recoil. These libraries offer lighter alternatives to Redux with simpler APIs for certain use cases.
What is the difference between a controlled and uncontrolled component in React?
The difference between controlled and uncontrolled components in React lies in how their form input values are managed.
A controlled component has its form data handled by React state. The component's state is the "single source of truth." Each state update re-renders the component.
JavaScript
function ControlledInput() {
const [value, setValue] = useState('');
const handleChange = (event) => {
setValue(event.target.value);
};
return (
<input type="text" value={value} onChange={handleChange} />
);
}
An uncontrolled component has its form data handled by the DOM itself. You get input values directly from the DOM, often using a ref.
JavaScript
import React, { useRef } from 'react';
function UncontrolledInput() {
const inputRef = useRef(null);
const handleSubmit = () => {
alert('Input value: ' + inputRef.current.value);
};
return (
<>
<input type="text" ref={inputRef} />
<button onClick={handleSubmit}>Submit</button>
</>
);
}
Controlled components offer more predictable behavior and easier validation. Uncontrolled components can be simpler for basic form fields.
How do you implement server-side rendering in a React application?
You implement server-side rendering (SSR) in a React application to improve initial load performance and SEO. SSR renders React components to HTML strings on the server.
You typically use a framework like Next.js for SSR in React. Next.js handles the complex setup.
Here's a basic example using Next.js:
Create a Next.js project:
Bash
npx create-next-app my-ssr-app
cd my-ssr-app
Create a page file (e.g., pages/index.js
). Next.js automatically treats files in the pages
directory as routes.
JavaScript
// pages/index.js
function HomePage({ data }) {
return (
<div>
<h1>Welcome!</h1>
<p>{data}</p>
</div>
);
}
export async function getServerSideProps() {
// This function runs on the server for each request
const res = await fetch('https://api.example.com/data');
const data = await res.json();
return {
props: { data: data.message }, // Will be passed to the page component as props
};
}
export default HomePage;
When a request comes in for /
, Next.js calls getServerSideProps
on the server. It fetches data, renders HomePage
to HTML, and sends that HTML to the client. The client then "hydrates" the static HTML into a fully interactive React application.
What is the purpose of the useMemo
hook in React?
The useMemo
hook in React lets you memoize expensive computations. It prevents re-calculating values on every re-render if their dependencies haven't changed.
useMemo
returns a memoized value. It only recomputes that value when one of its dependencies changes.
JavaScript
import React, { useState, useMemo } from 'react';
function ExpensiveCalculationComponent({ num1, num2 }) {
const [multiplier, setMultiplier] = useState(1);
// This computation is memoized
const result = useMemo(() => {
console.log('Performing expensive calculation...');
return (num1 + num2) * multiplier;
}, [num1, num2, multiplier]);
// Re-calculate only if num1, num2, or multiplier changes
return (
<div>
<p>Result: {result}</p>
<button onClick={() => setMultiplier(multiplier + 1)}>
Increase Multiplier
</button>
</div>
);
}
In this example, the result
calculation only re-runs if num1
, num2
, or multiplier
changes. If only other states in the component change, the result remains memoized.
How do you optimize the bundle size of a web application?
You optimize the bundle size of a web application to improve load times and overall performance.
Implement tree shaking. This process eliminates unused code from your final bundle. Modern bundlers like Webpack and Parcel support tree shaking. Ensure you use ES modules (import
/export
) for effective tree shaking.
Use dynamic imports (code splitting). This splits your code into smaller chunks. These chunks load on demand.
JavaScript
// Before (loads all_components.js immediately)
import { ComponentA } from './all_components';
// After (loads ComponentB.js only when needed)
const ComponentB = React.lazy(() => import('./ComponentB'));
Minify and Uglify your JavaScript, CSS, and HTML. This removes whitespace, comments, and shortens variable names. Build tools automate this.
Remove unused libraries or features. Audit your dependencies and eliminate any that are not actively used.
What is the difference between debounce and throttle in JavaScript?
Debounce and throttle are both used to limit how frequently a function is called, but they behave differently:
Debounce: The function is only called after a certain delay after the last event. It cancels the previous calls if new events keep coming in within the delay period.
Use case: Perfect for events like input fields, where you want to wait until the user stops typing before calling a function.
Debounce Example:
javascript
function debounce(func, delay) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func(...args), delay);
};
}
If you type in an input field, the debounce waits until you stop typing, then executes the function after a set delay.
Throttle: The function is called at regular intervals, no matter how many times the event happens. It makes sure the function is called at most once every specified period.
Use case: Useful for events like scrolling or window resizing, where you want to limit the number of calls to improve performance.
Throttle Example:
javascript
function throttle(func, delay) {
let lastTime = 0;
return function(...args) {
const now = new Date().getTime();
if (now - lastTime >= delay) {
func(...args);
lastTime = now;
}
};
}
If you're scrolling a webpage, throttle ensures the scroll event doesn't trigger a function call every millisecond, but only once every delay (e.g., 500ms).
How do you implement a custom directive in Angular?
You implement a custom directive in Angular to add behavior to elements or components. Directives are JavaScript classes declared with the @Directive()
decorator.
Here is a basic custom attribute directive that changes an element's background color on hover:
Generate the directive:
Bash
ng generate directive highlight
Edit the highlight.directive.ts
file:
TypeScript
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
@Directive({
selector: '[appHighlight]' // This makes it an attribute directive
})
export class HighlightDirective {
@Input() defaultColor: string = 'yellow';
// Default color input
@Input('appHighlight') highlightColor: string = '';
// Alias for directive name
constructor(private el: ElementRef) { }
// Listen for mouse enter event
@HostListener('mouseenter') onMouseEnter() {
this.highlight(this.highlightColor || this.defaultColor);
}
// Listen for mouse leave event
@HostListener('mouseleave') onMouseLeave() {
this.highlight('');
// Clear background
}
private highlight(color: string) {
this.el.nativeElement.style.backgroundColor = color;
}
}
Use the directive in an HTML template:
HTML
<p appHighlight="lightblue">Hover over this paragraph!</p>
<p appHighlight>This paragraph uses the default highlight color.</p>
This directive listens for mouse events and applies a background color based on inputs.
What is the purpose of the ngOnInit
lifecycle hook in Angular?
The ngOnInit
lifecycle hook in Angular is a method that runs once after Angular initializes a component's data-bound properties. It is a key hook for initialization logic.
You use ngOnInit
for tasks like:
- Initializing component state.
- Fetching data from a remote service.
- Setting up subscriptions to observables.
It runs only once after the first ngOnChanges
call.
TypeScript
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-my-component',
template: '<p>{{ message }}</p>',
})
export class MyComponent implements OnInit {
message: string = '';
constructor() {
console.log('Constructor called.'); // Called before ngOnInit
}
ngOnInit(): void {
console.log('ngOnInit called.');
// Called after data-bound properties are initialized
this.message = 'Component initialized and data fetched!';
// Example: fetch data here
// this.dataService.fetchData().subscribe(data => this.data = data);
}
}
ngOnInit
is a good place for setup that requires component's properties to be ready.
How do you test the accessibility of a web application?
You test the accessibility of a web application using a combination of automated tools and manual checks.
Automated tools quickly identify common accessibility issues.
- Lighthouse (built into Chrome DevTools): It provides an accessibility score and suggestions.
- axe DevTools (browser extension): It scans the page for accessibility violations and provides detailed reports.
- Pa11y (command-line tool): Automates accessibility testing across multiple pages.
Manual checks are crucial for issues that automated tools cannot detect.
- Keyboard navigation: Test if all interactive elements are reachable and operable using only the keyboard (Tab, Shift+Tab, Enter, Spacebar).
- Screen reader testing: Use a screen reader (e.g., NVDA, JAWS, VoiceOver) to navigate your application. Listen to how content is announced and ensure logical flow.
- Color contrast: Visually check for sufficient contrast between text and background colors, or use tools like WebAIM Contrast Checker.
- Zoom and responsiveness: Test how the layout and content adapt to different screen sizes and text zoom levels.
- Semantic HTML: Ensure you use appropriate HTML tags (e.g., <button>, <nav>, <main>) for their intended purpose.
Combine these methods for comprehensive accessibility testing.
What is the purpose of the role
attribute in HTML?
The role
attribute in HTML defines the purpose or role of an element in the context of assistive technologies. It is part of the WAI-ARIA (Web Accessibility Initiative - Accessible Rich Internet Applications) specification.
role
helps screen readers and other assistive technologies understand the semantic meaning of elements that might not have inherent semantics. For example, a generic div
might act as a button or a navigation menu.
Adding a role clarifies its purpose:
HTML
<div role="button" tabindex="0" aria-label="Submit form">Submit</div>
<ul role="menubar">
<li role="menuitem">File</li>
<li role="menuitem">Edit</li>
</ul>
The role
attribute does not change the element's visual appearance or behavior. It only provides semantic meaning to assistive technologies. It is crucial for creating accessible custom widgets.
How do you implement a skip navigation link in a web application?
You implement a skip navigation link to improve keyboard accessibility. This link allows keyboard users to bypass repetitive navigation links and jump directly to the main content area.
Here's how to implement it:
Place the skip link at the very top of your HTML <body>
. Make it visually hidden until focused.
HTML
<body>
<a href="#main-content" class="skip-link">Skip to main content</a>
<header>
<nav>...</nav>
</header>
<main id="main-content">
<h1>Welcome to our site</h1>
<p>This is the main content area.</p>
</main>
</body>
Add CSS to hide the link by default and reveal it on focus.
CSS
.skip-link {
position: absolute;
left: -9999px; /* Off-screen by default */
top: auto;
width: 1px;
height: 1px;
overflow: hidden;
z-index: -999;
}
.skip-link:focus {
left: auto;
top: auto;
width: auto;
height: auto;
overflow: auto;
position: static;
/* Make it visible and part of flow */
margin: 10px;
padding: 5px;
background-color: #eee;
border: 1px solid #333;
color: #333;
text-decoration: none;
z-index: 999;
}
When a user presses Tab after the page loads, the skip link becomes visible and gets focus. Pressing Enter on it will jump them to the element with id="main-content"
.
How do you implement a Git hook?
You implement a Git hook as a script that Git executes automatically before or after certain events, like committing or pushing. Hooks automate tasks and enforce policies.
Git hooks are located in the .git/hooks
directory of your repository. Each hook is a file named after the event (e.g., pre-commit
, post-merge
).
Here's an example of a pre-commit hook that checks for large files before a commit:
Navigate to your Git hooks directory:
Bash
cd .git/hooks
Create or edit the pre-commit
file. Make sure it's executable (chmod +x pre-commit
).
Bash
#!/bin/sh
# Check for large files
MAX_FILE_SIZE_KB=1024 # 1 MB
for file in $(git diff --cached --name-only);
do
if [ -f "$file" ]; then # Check if file exists
file_size=$(du -k "$file" | cut -f1) # Get file size in KB
if [ "$file_size" -gt "$MAX_FILE_SIZE_KB" ];
then
echo "Error: File $file is too large ($file_size KB). Max allowed is $MAX_FILE_SIZE_KB KB."
exit 1 # Abort commit
fi
fi
done
exit 0 # Allow commit
This script runs before each commit. If it finds a file larger than 1MB, it prints an error and prevents the commit.
What is the purpose of the git cherry-pick
command?
The git cherry-pick
command applies specific commits from one branch onto another. It copies a single commit (or a series of commits) and creates new commits with the same changes on the current branch.
You use git cherry-pick
when you need a specific change from another branch but do not want to merge the entire branch.
For example, to apply commit abc1234
from another branch to your current branch:
Switch to the target branch:
Bash
git checkout feature/my-branch
Cherry-pick the commit:
Bash
git cherry-pick abc1234
This creates a new commit on feature/my-branch
that contains the exact changes from commit abc1234
. The original commit abc1234
remains on its original branch.
How do you revert a commit in Git?
You revert a commit in Git using two main commands: git revert
or git reset
. The choice depends on whether you want to preserve history or modify it.
git revert
creates a new commit that undoes the changes introduced by a previous commit. This preserves the project history. It is safe for commits already pushed to a shared remote repository.
Bash
git revert <commit-hash>
This command opens your default editor to confirm the new revert commit message. The original commit still exists in the history.
git reset
moves the HEAD pointer to a specified commit. It effectively rewrites history. This is suitable for undoing local, unpushed commits.
git reset --soft <commit-hash>
: Moves HEAD, but keeps changes in the staging area.git reset --mixed <commit-hash>
(default): Moves HEAD, but unstages changes. Files remain in your working directory.git reset --hard <commit-hash>
: Moves HEAD and discards all changes in the working directory and staging area. Use with caution, as it permanently deletes uncommitted work.
Bash
git reset --hard HEAD~1 # Go back one commit, discarding changes
Choose git revert
for published history and git reset
for local history modification.
How do you implement end-to-end testing in a web application?
You implement end-to-end (E2E) testing to simulate real user scenarios in your web application. E2E tests interact with the application through its UI, verifying the entire flow from client to server.
You use E2E testing frameworks like Cypress. Cypress runs tests directly in a browser.
Here's an outline of an E2E test using Cypress:
Install Cypress:
Bash
npm install cypress --save-dev
Open Cypress:
Bash
npx cypress open
This launches the Cypress Test Runner.
Create a test file (e.g., cypress/e2e/login.cy.js
):
JavaScript
// cypress/e2e/login.cy.js
describe('Login Page', () => {
beforeEach(() => {
cy.visit('/login'); // Visit the login page before each test
});
it('should allow a user to log in successfully', () => {
cy.get('input[name="username"]').type('testuser'); // Type into username field
cy.get('input[name="password"]').type('password123'); // Type into password field
cy.get('button[type="submit"]').click(); // Click the submit button
cy.url().should('include', '/dashboard'); // Assert URL changed to dashboard
cy.contains('Welcome, testuser').should('be.visible'); // Assert welcome message is visible
});
it('should show an error for invalid credentials',
() => {
cy.get('input[name="username"]').type('wronguser');
cy.get('input[name="password"]').type('wrongpassword');
cy.get('button[type="submit"]').click();
cy.contains('Invalid credentials').should('be.visible'); // Assert error message
});
});
This Cypress test simulates a user logging in. It interacts with input fields, clicks buttons, and asserts on URL changes and visible text.
What is the purpose of snapshot testing in React?
The purpose of snapshot testing in React is to detect unintended UI changes. A snapshot test records the rendered output of a component and saves it as a "snapshot." Subsequent test runs compare the current component output to the saved snapshot.
You typically use Jest for snapshot testing in React.
Here's how it works:
Initial run: When you run the test for the first time, Jest renders the component. It then saves its serialized output (usually to a .snap
file).
JavaScript
// MyComponent.test.js
import renderer from 'react-test-renderer';
import MyComponent from './MyComponent';
it('renders correctly', () => {
const tree = renderer.create(<MyComponent />).toJSON();
expect(tree).toMatchSnapshot(); // Creates the snapshot file
});
Subsequent runs: Jest renders the component again. It compares the new output to the existing snapshot file. If they match, the test passes.
If they differ, the test fails. Jest shows you the differences. You can then inspect the changes. If the change is intended, you update the snapshot (jest --updateSnapshot
).
If unintended, you fix the component.
Snapshot testing is useful for ensuring that UI components do not change unexpectedly over time.
How do you mock API calls in a unit test?
You mock API calls in a unit test to isolate the code under test from external dependencies. This ensures that your tests are fast, reliable, and consistent.
You typically use a testing framework like Jest for mocking.
Here's an example using Jest's mocking capabilities to mock an API call made by fetch
:
JavaScript
// dataService.js (the code you want to test)
async function fetchData() {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
}
export { fetchData };
JavaScript
// dataService.test.js (your unit test file)
import { fetchData } from './dataService';
// Mock the global fetch function
global.fetch = jest.fn(() =>
Promise.resolve({
json: () => Promise.resolve({ message: 'Mocked data' }),
})
);
describe('fetchData', () => {
it('should fetch data successfully', async () => {
const data = await fetchData();
expect(data).toEqual({ message: 'Mocked data' }); // Assert against mocked data
expect(fetch).toHaveBeenCalledTimes(1); // Verify fetch was called
expect(fetch).toHaveBeenCalledWith('https://api.example.com/data'); // Verify correct URL
});
});
In this test, global.fetch
is replaced with a Jest mock function. This mock returns a controlled response. The fetchData
function then uses this mocked response instead of making a real network request.
What is the difference between Webpack and Parcel bundlers?
Webpack and Parcel are both module bundlers. They take various assets (JavaScript, CSS, images) and combine them into optimized bundles for browsers. They differ mainly in their configuration approach and ease of use.
Webpack is a highly configurable and powerful bundler.
- Configuration: Requires extensive configuration files (
webpack.config.js
). You define loaders, plugins, and entry/output points explicitly. - Flexibility: Offers granular control over the bundling process. It supports complex setups, custom optimizations, and specific build pipelines.
- Learning Curve: Has a steeper learning curve due to its configuration complexity.
- Use Cases: Favored for large, complex applications that need fine-tuned control over the build process.
Parcel is a zero-configuration bundler.
- Configuration: Requires minimal to no configuration. It automatically detects and processes files.
- Ease of Use: Focuses on developer experience and speed. You just point it to an entry file.
- Learning Curve: Has a very low learning curve, making it quick to get started.
- Use Cases: Ideal for small to medium-sized projects, rapid prototyping, and developers who prefer less setup overhead.
In summary, Webpack offers maximum control with more configuration, while Parcel offers simplicity with less configuration.
How do you optimize the build process for a large web application?
You optimize the build process for large web applications to reduce build times and improve developer productivity.
Implement parallel builds. Use tools that can run different parts of the build process simultaneously. For example, some task runners or CI/CD pipelines can execute multiple build steps in parallel across different cores or machines.
Utilize caching strategies. Cache intermediate build artifacts. If a file or module hasn't changed, the bundler can reuse its previously processed output instead of re-processing it.
- Persistent Caching: Webpack 5 supports persistent caching, which stores build results to disk.
- Module Caching: Tools like Babel or ESLint can cache results for individual files.
Minimize file I/O operations. Reading and writing many small files is slow. Combine steps that involve file system access where possible.
Optimize tooling configuration.
- Webpack: Use
thread-loader
orcache-loader
for expensive loaders. Configureexternals
to avoid bundling large libraries already available via CDN. - TypeScript: Use
isolatedModules
to enable faster transpilation.
Incremental builds: Set up your build system to only re-build parts of the application that have changed, rather than rebuilding everything.
How do you implement a custom element in web components?
You implement a custom element to create new HTML tags with custom behavior and encapsulated styling. Custom elements are a core part of Web Components.
Here's how to define a custom tag with JavaScript:
Define a class that extends HTMLElement
. This class contains the element's logic and lifecycle callbacks.
JavaScript
// my-custom-element.js
class MyCustomElement extends HTMLElement {
constructor() {
super();
// Always call super() first
this.message = 'Hello from My Custom Element!';
}
// Called when the element is added to the DOM
connectedCallback() {
this.innerHTML = `
<div>
<p>${this.message}</p>
<button id="my-button">Click Me</button>
</div>
`;
this.querySelector('#my-button').addEventListener('click', () => {
alert('Button clicked inside custom element!');
});
}
// Called when the element is removed from the DOM
disconnectedCallback() {
// Clean up event listeners or resources
console.log('MyCustomElement disconnected');
}
// Other lifecycle callbacks: attributeChangedCallback, adoptedCallback
}
Register the custom element using customElements.define()
. This maps your class to a custom HTML tag. The tag name must contain a hyphen.
JavaScript
customElements.define('my-custom-element', MyCustomElement);
Use the custom element in your HTML:
HTML
<!DOCTYPE html>
<html>
<head>
<script type="module" src="my-custom-element.js"></script>
</head>
<body>
<my-custom-element></my-custom-element>
</body>
</html>
When the browser encounters <my-custom-element>
, it uses your defined class to render and manage its behavior.
What is the purpose of the Shadow DOM in web components?
The Shadow DOM is a key feature of Web Components. Its purpose is to provide encapsulation for the DOM and CSS of a component. It allows you to attach a separate, hidden DOM tree to an element. This "shadow tree" is isolated from the main document's DOM.
Key benefits of Shadow DOM:
- CSS Scoping: Styles defined within the Shadow DOM only apply to the elements inside that shadow tree. They do not leak out to the main document. This prevents style conflicts.
- DOM Encapsulation: The DOM structure inside the shadow tree is isolated. External JavaScript cannot easily access or modify elements within it without explicitly traversing the shadow boundary.
- Simplified Development: You can build reusable components without worrying about them clashing with other parts of the page.
Here's how you attach a Shadow DOM:
JavaScript
// Assuming 'my-element' is an instance of a custom element
const shadowRoot = myElement.attachShadow({ mode: 'open' });
// 'open' or 'closed'
shadowRoot.innerHTML = `
<style>
p {
color: blue;
/* This style only affects paragraphs inside the shadow DOM */
}
</style>
<p>This text is inside the Shadow DOM.</p>
`;
The <p>
element inside shadowRoot
will have blue text. A <p>
element outside of this shadow DOM will not be affected.