Have you noticed how Google shows search suggestions while you're still typing? You don't have to press Enter or wait for the page to reload. The suggestions simply appear as you type.
Or think about adding a product to your shopping cart. You click the "Add to Cart" button, and the cart count changes immediately. The rest of the page stays exactly where it is.
How do websites do this?
One of the techniques that makes this possible is AJAX.
In this article, we'll understand what AJAX is, how it works, and how to use it in JavaScript. We'll also build a small example to see it in action.
What is AJAX?
AJAX stands for Asynchronous JavaScript and XML.
It's a technique that allows a webpage to communicate with a server and exchange data without having to reload the entire page.
Let's understand this with an example.
Imagine you're visiting an online shopping website. You find a product you like and click the "Add to Cart" button.
Now, the website needs to tell the server that you've added a product to your cart.
One way to do this would be to submit a form and reload the page. The server processes your request and sends back a new page with the updated cart information.
That works, but reloading the entire page just to update a shopping cart isn't always necessary.
With AJAX, JavaScript can send the request in the background. Once the server responds, JavaScript updates the cart count on the page.
You can continue browsing without being interrupted by a page reload.
That's the basic idea behind AJAX.
One thing worth remembering is that AJAX isn't a programming language or a JavaScript library. It's a technique that uses technologies already available in web browsers.
Why do we need AJAX?
To understand why AJAX is useful, it helps to look at how web applications traditionally communicate with servers.
Without AJAX
Consider a webpage displaying a list of products.
You select a category to filter the products. The browser sends a request to the server, which processes it and returns a new HTML page containing the filtered results.
The browser then displays that page.
The problem is that the browser may have to load an entirely new document, even though you only wanted to update the product list.
With AJAX
Now consider the same website using AJAX.
When you select a category, JavaScript sends a request to the server asking for products in that category.
The server returns the matching products, usually as JSON.
JavaScript reads the response and replaces the existing product list with the new results.
The navigation bar, search box, and other parts of the page remain unchanged.
This can reduce unnecessary data transfers and make the website feel more responsive.
Of course, AJAX doesn't automatically make every website faster. That still depends on how the application and server are built. But it gives developers much more control over what gets updated.
How does AJAX work?
Let's take a simple example.
Suppose we have a webpage with a button called "Load Users".
When someone clicks this button, we want to retrieve a list of users from our server and display their names on the page.
Here's what happens behind the scenes:
- The user clicks the "Load Users" button.
- JavaScript sends an HTTP request to the server.
- The server receives the request and processes it.
- The server sends back the user details.
- JavaScript receives the response and updates the webpage.
For example, the server might return the following JSON:
[
{
"id": 1,
"name": "John",
"email": "john@example.com"
},
{
"id": 2,
"name": "Sarah",
"email": "sarah@example.com"
}
]JavaScript can read this data and display the users in an HTML list.
Notice that the server isn't necessarily sending an entire HTML page. It only sends the information we need.
JavaScript takes care of displaying it.
This separation between retrieving data and displaying it is common in modern web development.
What does "asynchronous" mean?
We've been talking about sending requests in the background. But what exactly does that mean?
The answer is in the first letter of AJAX: Asynchronous.
Let's use a simple example.
Imagine you're ordering food at a restaurant.
You place your order at the counter. The food will take about 15 minutes to prepare.
You have two choices.
Synchronous approach: You stand at the counter and wait until your order is ready. You don't do anything else during that time.
Asynchronous approach: You place your order, get a token, and return to your table. You can talk to your friends or do something else while the kitchen prepares your food. When the order is ready, you're notified.
AJAX works more like the second approach.
When JavaScript sends an asynchronous request, it doesn't have to stop the entire webpage from responding to the user while waiting for the server.
Other JavaScript tasks and user interactions can continue.
When the response becomes available, JavaScript can process it and update the page.
This is especially useful when a server takes some time to respond.
Does AJAX still use XML?
You might be wondering why AJAX has XML in its name when the examples we've seen use JSON.
That's because XML was a popular format for exchanging data when AJAX became widely used.
Here's what an XML response might look like:
<user>
<id>1</id>
<name>John</name>
<email>john@example.com</email>
</user>Today, most web APIs use JSON instead.
The same information in JSON would look like this:
{
"id": 1,
"name": "John",
"email": "john@example.com"
}JSON is generally more convenient to work with in JavaScript because it can be converted directly into JavaScript objects.
Despite its name, AJAX isn't limited to XML. You can exchange JSON, HTML, plain text, XML, and other types of data.
In fact, you'll probably use JSON for most AJAX requests you write today.
How to make AJAX requests in JavaScript
Now that we understand the idea, let's look at how to implement it.
There are two important browser APIs you should know about:
- XMLHttpRequest (XHR): The traditional API used for AJAX requests.
- Fetch API: A newer, Promise-based API commonly used in modern JavaScript applications.
We'll start with XMLHttpRequest because it helps explain how AJAX was traditionally implemented.
Then we'll move on to Fetch, which is what I'd recommend learning for most new projects.
1. AJAX using XMLHttpRequest
Before the Fetch API became available, XMLHttpRequest was the standard way to make AJAX requests.
Despite its name, XMLHttpRequest can work with JSON and other data formats, not just XML.
Here's a basic example:
const xhr = new XMLHttpRequest();
xhr.open("GET", "/api/users", true);
xhr.onload = function () {
if (xhr.status >= 200 && xhr.status < 300) {
const users = JSON.parse(xhr.responseText);
console.log(users);
} else {
console.error("Request failed:", xhr.status);
}
};
xhr.onerror = function () {
console.error("Network error");
};
xhr.send();This code sends a GET request to /api/users and prints the returned data in the browser console.
Let's go through it.
Creating the request
const xhr = new XMLHttpRequest();First, we create an instance of XMLHttpRequest.
This object provides the methods and properties we need to communicate with the server.
Configuring the request
xhr.open("GET", "/api/users", true);The open() method configures our request.
Here, we're passing three arguments:
GETis the HTTP method. We're requesting information from the server./api/usersis the URL of the API endpoint.truetells the browser to make an asynchronous request.
The API endpoint in this example is just a placeholder. For the code to work, your server must have an endpoint that responds to /api/users.
Reading the response
xhr.onload = function () {
if (xhr.status >= 200 && xhr.status < 300) {
const users = JSON.parse(xhr.responseText);
console.log(users);
}
};The onload event handler runs when the request completes and the response has been received.
We check the HTTP status code to find out whether the request was successful.
Status codes from 200 to 299 generally indicate success.
Next, we use JSON.parse() to convert the JSON response into a JavaScript value.
We can then work with that data just like any other JavaScript object or array.
Sending the request
xhr.send();Finally, the send() method starts the request.
That's all we need to make a simple AJAX request using XMLHttpRequest.
It works, but you can probably see that we need quite a bit of code for such a simple operation.
This is one reason why the Fetch API became popular.
2. AJAX using the Fetch API
The Fetch API gives us a simpler way to make HTTP requests.
It uses JavaScript Promises, which make asynchronous code easier to organize.
Let's make the same request using Fetch.
fetch("/api/users")
.then(response => {
if (!response.ok) {
throw new Error("Failed to load users");
}
return response.json();
})
.then(users => {
console.log(users);
})
.catch(error => {
console.error(error);
});We're doing essentially the same thing as the previous XMLHttpRequest example, but with fewer lines of code.
Here's what's happening.
First, we call:
fetch("/api/users")This sends an HTTP GET request to the specified URL.
The fetch() function returns a Promise. A Promise represents a result that may become available later.
Once the server responds, the first then() callback runs.
.then(response => {
if (!response.ok) {
throw new Error("Failed to load users");
}
return response.json();
})We check whether the HTTP response was successful.
Then we call response.json() to read and parse the JSON response body.
One thing to know about Fetch is that HTTP errors such as 404 and 500 don't automatically cause the Promise to reject.
That's why we're checking response.ok ourselves.
The next then() receives the parsed data.
.then(users => {
console.log(users);
})And if a network error occurs, or if our code throws an error, the catch() callback handles it.
.catch(error => {
console.error(error);
});Fetch is easier to work with than XMLHttpRequest in many situations. But we can make this example even more readable.
Using Fetch with async and await
If you're familiar with modern JavaScript, you've probably come across async and await.
These keywords allow us to write asynchronous code in a way that looks similar to regular sequential code.
Here's our previous Fetch example rewritten using async/await:
async function getUsers() {
try {
const response = await fetch("/api/users");
if (!response.ok) {
throw new Error("Failed to load users");
}
const users = await response.json();
console.log(users);
} catch (error) {
console.error(error);
}
}
getUsers();Personally, I find this version easier to read, especially when a function contains multiple asynchronous operations.
Let's understand the two important keywords.
`async` is used to declare an asynchronous function. An async function always returns a Promise.
`await` pauses execution of the surrounding async function until the Promise settles. It doesn't block the entire browser while waiting.
Notice that we're using await twice.
The first one waits for the HTTP response:
const response = await fetch("/api/users");The second waits for the response body to be read and parsed as JSON:
const users = await response.json();We also use try and catch to handle errors.
If you're just getting started with AJAX, I'd recommend focusing on the Fetch API with async/await. You'll find it useful when working with frontend frameworks and backend APIs.
Practical example: Loading users without refreshing the page
Enough theory. Let's build something that actually works.
We'll create a webpage with a button labeled "Load Users".
When the button is clicked, we'll fetch some user information from an API and display it on the page.
For this example, we'll use JSONPlaceholder, a free fake REST API commonly used for testing and learning.
You don't need to create a backend server for this example because JSONPlaceholder already provides the data.
Create a file named index.html and add the following code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0">
<title>AJAX Example</title>
</head>
<body>
<h1>AJAX User List</h1>
<button id="loadButton">Load Users</button>
<p id="status" role="status"></p>
<ul id="userList"></ul>
<script>
const button = document.getElementById("loadButton");
const status = document.getElementById("status");
const userList = document.getElementById("userList");
button.addEventListener("click", async function () {
button.disabled = true;
status.textContent = "Loading users...";
userList.replaceChildren();
try {
const response = await fetch(
"https://jsonplaceholder.typicode.com/users"
);
if (!response.ok) {
throw new Error("Failed to load users");
}
const users = await response.json();
users.forEach(user => {
const li = document.createElement("li");
li.textContent =
`${user.name} - ${user.email}`;
userList.appendChild(li);
});
status.textContent = "Users loaded successfully!";
} catch (error) {
status.textContent =
"Unable to load users. Please try again.";
console.error(error);
} finally {
button.disabled = false;
}
});
</script>
</body>
</html>Open this file in your browser.
You'll see a heading and a button. Initially, the user list will be empty.
Click the "Load Users" button.
The browser sends a request to JSONPlaceholder, retrieves the user details, and displays their names and email addresses.
And the page doesn't reload!
Understanding what happens
Let's look at the important parts of the code.
First, we attach a click event listener to the button.
button.addEventListener("click", async function () {
// Our AJAX code goes here
});This function runs whenever the user clicks the button.
Inside it, we send the HTTP request:
const response = await fetch(
"https://jsonplaceholder.typicode.com/users"
);The API returns an array of user objects.
We convert the JSON response into JavaScript data:
const users = await response.json();Now comes the interesting part.
users.forEach(user => {
const li = document.createElement("li");
li.textContent = `${user.name} - ${user.email}`;
userList.appendChild(li);
});We're looping through the users and creating a new <li> element for each one.
We then add those elements to the existing HTML list.
This is where the webpage actually changes.
The browser doesn't need a new HTML document. JavaScript simply modifies the elements that are already on the page.
We're also using textContent rather than innerHTML. This is a good practice when displaying data received from an API because it prevents that data from being interpreted as HTML.
The example also handles loading and error states, so users know what's happening if the request takes time or fails.
Sending data using AJAX
Until now, we've only used AJAX to retrieve information from a server.
But AJAX can also send data.
Think about a contact form.
Normally, submitting an HTML form might cause the browser to navigate to another page.
Using JavaScript and Fetch, we can send the form data to the server and display a success or error message without leaving the current page.
Here's an example:
async function submitForm() {
const data = {
name: "John",
email: "john@example.com",
message: "Hello!"
};
try {
const response = await fetch("/api/contact", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
});
if (!response.ok) {
throw new Error("Submission failed");
}
console.log("Form submitted successfully");
} catch (error) {
console.error(error);
}
}Notice that we're passing an additional object to fetch().
Let's look at what it contains.
The HTTP method
method: "POST"We're using POST because we want to submit information to the server.
The request headers
headers: {
"Content-Type": "application/json"
}This tells the server that the request body contains JSON.
The request body
body: JSON.stringify(data)The JSON.stringify() method converts our JavaScript object into a JSON string.
The server can then read and process that data.
Keep in mind that /api/contact is just an example endpoint. You'll need a backend application that accepts the request.
AJAX isn't limited to GET and POST requests. You can also use HTTP methods such as PUT, PATCH, and DELETE when an API supports them.
Where is AJAX used in real applications?
You've probably interacted with AJAX-based features many times without realizing it.
Here are a few common examples.
Search suggestions
When you type something into a search box, the website can send your search text to the server and retrieve matching suggestions.
The suggestions appear below the input field without reloading the page.
Checking username availability
Imagine you're creating an account and entering a username.
The website can check whether that username is available by sending a request to the server while you're filling out the form.
Infinite scrolling
On some websites, more content appears as you scroll down.
Instead of loading everything at once, the application fetches additional content when needed.
Shopping carts
When you add a product to your cart, the website can send the product details to the server and update the cart count immediately.
Notifications
A website can periodically request new notifications and update the notification count.
Some applications use WebSockets or Server-Sent Events instead when they need the server to push updates automatically.
Pagination and filtering
When you're viewing a large table of records, you might want to filter the results or move to another page.
AJAX allows the application to retrieve the required records and update the table without reloading the entire page.
Advantages of AJAX
The biggest advantage of AJAX is that it lets us update the parts of a webpage that actually need to change.
Instead of repeatedly loading the entire page, we can request specific data and display it where it's needed.
This can improve the user experience, especially in applications where users frequently interact with forms, tables, search fields, or other dynamic components.
It can also reduce unnecessary data transfers.
For example, if a webpage contains a large navigation menu, header, footer, and sidebar, there's usually no reason to download all of that again just to update a small list.
With AJAX, we can retrieve the list data alone.
Another advantage is that users can continue interacting with the webpage while an asynchronous request is in progress.
However, these benefits depend on how well the application is implemented. Too many unnecessary requests or inefficient JavaScript can still make a website slow.
Are there any disadvantages?
AJAX is useful, but there are a few things developers need to keep in mind.
Network errors: Requests can fail. A user might lose their internet connection, the server might be unavailable, or the API might return an error. We should handle these cases instead of assuming every request will succeed.
Loading states: When a request takes time, users need some indication that something is happening. A loading message or spinner can help.
JavaScript dependency: If an important feature depends entirely on JavaScript, it may not work when JavaScript is disabled or fails to load. Depending on the application, providing a fallback may be useful.
Security: Data received from a server shouldn't automatically be trusted. Similarly, the backend must validate incoming requests and enforce proper authentication and authorization. AJAX requests can also be affected by security issues such as XSS and CSRF.
CORS restrictions: Browsers apply security rules when JavaScript requests resources from another origin. If an API doesn't allow requests from your website's origin, the browser may block JavaScript from accessing the response. This is where Cross-Origin Resource Sharing (CORS) comes into the picture.
These aren't reasons to avoid AJAX. They're simply things to consider when building applications that communicate with servers.
AJAX vs Fetch API: Are they the same?
This is a common point of confusion, especially for beginners.
AJAX and Fetch are related, but they aren't the same thing.
AJAX is a technique. Fetch is an API.
AJAX describes the general approach of communicating with a server asynchronously and updating a webpage without a full reload.
Fetch is one of the browser APIs we can use to make those requests.
Before Fetch became available, developers commonly used XMLHttpRequest. Libraries such as jQuery also provided simpler methods for making AJAX requests.
Today, we can achieve the same result using Fetch.
So when you're using Fetch to retrieve data from a server and update your webpage dynamically, you're essentially implementing AJAX.
Is AJAX still used today?
Yes. Very much.
You may not hear the word AJAX as often as you did several years ago, but the underlying technique is still common in web development.
Modern applications frequently communicate with backend APIs using JavaScript without reloading the entire page.
Frameworks such as Angular, React, and Vue make it easier to build interfaces that update dynamically.
For example, Angular provides an HttpClient service that can send HTTP requests and process server responses.
React applications commonly use Fetch or other HTTP libraries to retrieve data.
Even if the code looks different from traditional XMLHttpRequest examples, the basic idea remains the same.
The browser requests data, receives a response, and updates the relevant part of the interface.
It's also worth mentioning that not every modern web application needs AJAX for everything. Traditional form submissions, server-side rendering, and regular page navigation still have their place.
The right approach depends on what you're building.
Conclusion
AJAX is actually a fairly simple concept once you understand what it's trying to achieve.
Suppose you need to update a small section of your webpage based on information from a server.
Instead of reloading the entire page, you can use JavaScript to request the data and update that section directly.
That's AJAX.
You can implement it using XMLHttpRequest, but for most new JavaScript projects, the Fetch API with async/await is a good choice.
If you're learning web development, try building a few small projects using Fetch. Start by loading data from a public API. Then try sending data using POST requests, handling errors, and displaying loading messages.
Once you're comfortable with those basics, working with APIs in Angular, React, Vue, or plain JavaScript becomes much easier.