Browsers have become incredibly powerful. Features that used to require heavy JavaScript libraries are now built right into the browser. And honestly, it’s about time. Let me walk you through the Web APIs that are replacing entire libraries and making your bundle sizes way smaller.
All practical examples are here for you: 👇
1. View Transitions API
Back then, you needed to install Framer Motion, GSAP, or some other animation library for smooth page transitions. Now the View Transitions API handles all of this natively, and it’s actually pretty amazing.
For example, you want smooth transitions between pages in your app. Before, you’d install a library, manage state, and handle animations manually. Now?
// Single-page app transitions
function navigateToNewView() {
if (!document.startViewTransition) {
// Fallback for older browsers
updateDOM();
return;
}
document.startViewTransition(() => {
updateDOM();
});
}
The browser takes a snapshot of the old view, you update the DOM, and then it takes another snapshot and smoothly animates between them. No library needed.
For multi-page apps, it’s even simpler. Just add this CSS:
@view-transition {
navigation: auto;
}
/* Customize specific elements */
.hero-image {
view-transition-name: hero;
}
Now when users navigate between pages, elements with the same view-transition-name will morph smoothly into each other. It's like magic, but it's just the browser doing its job.
Browser Support:
Chrome 111+, Edge 111+, Safari 18+, Firefox 144+ (as of October 2025). This is now Baseline Newly Available, meaning it works across all major browsers.
What it replaces:
Framer Motion, React Router animations, GSAP for page transitions, custom animation libraries.
2. Popover API
Creating modals, tooltips, and dropdowns used to be painful. You’d install something like Tippy.js Floating UI or build your own with tons of JavaScript for positioning, focus management, and accessibility.
The Popover API handles all of this declaratively. And you can build a complete modal with zero JavaScript.
<button popovertarget="my-modal">Open Modal</button>
<div id="my-modal" popover>
<h2>I'm a modal!</h2>
<p>Click outside to close, or press Escape.</p>
<button popovertarget="my-modal" popovertargetaction="hide">Close</button>
</div>
The browser handles:
- Showing/hiding the popover
- Light dismiss (clicking outside closes it)
- Keyboard support (Escape key closes it)
- Focus management
- Accessibility attributes
- Top layer positioning (no
z-indexbattles!)
Want a tooltip that shows on hover? Use popover="hint". Want a dropdown menu? Use popover="auto". Need a strict modal that doesn't close on an outside click? Use popover="manual".
/* Style the open state */
[popover]:popover-open {
opacity: 1;
transform: translateY(0);
}
/* Style the backdrop */
[popover]::backdrop {
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(4px);
}
Browser Support:
Chrome 114+, Edge 114+, Safari 17+, Firefox 125+. Became Baseline Newly Available in January 2025.
What it actually replaced:
Tippy.js, Popper.js, Floating UI, Bootstrap Modals, and custom modal solutions.
3. CSS Container Queries
You know how with media queries, we define specific styles based on the viewport size. With container queries, we can do the same, but instead of viewport size, we define style based on the container size or element size.
You want a component to adapt based on its container size? Install a library or write tons of JavaScript.
Container queries change everything. Components can now respond to their own container’s size, not the viewport.
.card-container {
container-type: inline-size;
}
@container (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 1fr 2fr;
}
}
Your card component adapts based on how much space it has, not how wide the browser window is. This is huge for component-based design.
Browser Support:
Chrome 105+, Edge 105+, Safari 16+, Firefox 110+. Baseline Widely Available since February 2023.
What do we not need anymore?
Element Queries polyfills, JavaScript-based responsive components, and complex media query logic.
4. Web Animations API
CSS animations are great until you need dynamic control. The Web Animations API gives you full programmatic control over animations while keeping them performant.
const element = document.querySelector('.box');
const animation = element.animate([
{ transform: 'translateX(0px)', opacity: 1 },
{ transform: 'translateX(300px)', opacity: 0 }
], {
duration: 1000,
easing: 'ease-in-out',
fill: 'forwards'
});
// Control it programmatically
animation.pause();
animation.play();
animation.reverse();
animation.currentTime = 500; // Jump to middle
You get all the performance benefits of CSS animations with JavaScript control. No library needed.
Browser Support: All modern browsers.
What it actually replaced:
Anime.js, Velocity.js, and parts of GSAP for DOM animations.
5. Intersection Observer
Writing scroll event listeners to check if elements were visible? Terrible for performance. Intersection Observer does this natively and efficiently.
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// Element is visible
entry.target.classList.add('visible');
// Stop observing if you don't need to anymore
observer.unobserve(entry.target);
}
});
});
// Watch elements
document.querySelectorAll('.lazy-load').forEach(el => {
observer.observe(el);
});
Perfect for lazy loading images, infinite scroll, triggering animations when elements come into view, analytics tracking.
Browser Support: All modern browsers.
No need for:
jQuery viewport plugins, custom scroll listeners, lazysizes library.
6. ResizeObserver
Before ResizeObserver, knowing when an element changed size was a nightmare. Window resize events don't help if your element changes size due to content changes or CSS.
const observer = new ResizeObserver(entries => {
entries.forEach(entry => {
const width = entry.contentRect.width;
const height = entry.contentRect.height;
console.log(`Element is now ${width}x${height}`);
// Update charts, adjust layouts, whatever you need
});
});
observer.observe(document.querySelector('.responsive-element'));
This is perfect for responsive charts, dynamic layouts, or any component that needs to react to size changes.
Browser Support: All modern browsers.
What it replaces: Element-resize-detector, ResizeSensor libraries, window resize hacks.
7. Clipboard API
Copying text to the clipboard used to involve creating invisible textareas, selecting them, executing document commands, it was hacky and unreliable.
The Clipboard API makes it clean and simple.
// Copy text
async function copyText(text) {
try {
await navigator.clipboard.writeText(text);
console.log('Copied!');
} catch (err) {
console.error('Failed to copy:', err);
}
}
// Read from clipboard
async function pasteText() {
try {
const text = await navigator.clipboard.readText();
console.log('Pasted:', text);
} catch (err) {
console.error('Failed to read:', err);
}
}
It even works with images and other data types!
// Copy image
async function copyImage(blob) {
await navigator.clipboard.write([
new ClipboardItem({ 'image/png': blob })
]);
}
Browser Support: All modern browsers (requires HTTPS and user interaction).
What it replaces: clipboard.js, ZeroClipboard, custom copy solutions.
8. FormData API
Collecting form data used to mean querying every input manually. FormData grabs everything in one go.
const form = document.querySelector('form');
form.addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(form);
// Send directly to server
const response = await fetch('/api/submit', {
method: 'POST',
body: formData
});
console.log('Done!');
});
// Or convert to object
const data = Object.fromEntries(formData.entries());
Files, text inputs, checkboxes, everything gets collected automatically. You can even add extra data programmatically.
Browser Support: All modern browsers.
What it replaces: jQuery serialize, custom form serialization libraries, manual input querying.
9. Web Storage API
Want to save user preferences or app state? localStorage and sessionStorage make it simple. No database is needed for client-side data.
// Save complex data
const user = {
name: 'Alex',
theme: 'dark',
preferences: { notifications: true }
};
localStorage.setItem('user', JSON.stringify(user));
// Retrieve it
const savedUser = JSON.parse(localStorage.getItem('user'));
// Session-only data
sessionStorage.setItem('tempData', 'This disappears when tab closes');
localStorage persists across sessions. sessionStorage clears when the tab closes. Both are synchronous and simple to use.
Browser Support: All modern browsers.
What it replaces: Cookies for client-side storage, PersistentStorage polyfills, simple database needs.
10. Geolocation API: Location Without Libraries
Building location-aware apps? The Geolocation API gives you coordinates instantly.
if ('geolocation' in navigator) {
navigator.geolocation.getCurrentPosition(
(position) => {
const lat = position.coords.latitude;
const lng = position.coords.longitude;
const accuracy = position.coords.accuracy;
console.log(`You're at ${lat}, ${lng} (±${accuracy}m)`);
// Show nearby restaurants, weather, stores, whatever
},
(error) => {
console.error('Location access denied');
}
);
}
You can even watch position changes for live tracking:
const watchId = navigator.geolocation.watchPosition(
(position) => {
updateMapMarker(position.coords);
}
);
// Stop watching later
navigator.geolocation.clearWatch(watchId);
Browser Support: All modern browsers (requires HTTPS and user permission).
What it replaces: Google Maps Geolocation API for simple location needs, custom geolocation libraries.
11. MutationObserver
Need to know when the DOM changes? Maybe you’re dealing with content injected by third-party scripts or building developer tools.
const observer = new MutationObserver((mutations) => {
mutations.forEach(mutation => {
if (mutation.type === 'childList') {
console.log('Nodes added/removed:', mutation.addedNodes, mutation.removedNodes);
}
if (mutation.type === 'attributes') {
console.log('Attribute changed:', mutation.attributeName);
}
});
});
observer.observe(document.body, {
childList: true,
subtree: true,
attributes: true,
characterData: true
});
Perfect for reacting to dynamic content, implementing undo/redo, or building tools that need to track DOM changes.
Browser Support: All modern browsers.
What it replaces: Mutation Events (deprecated), DOM polling, custom change detection.
12. Fetch API with Streams
The Fetch API supports response streams, meaning you can track download progress natively.
async function downloadWithProgress(url) {
const response = await fetch(url);
const reader = response.body.getReader();
const contentLength = response.headers.get('Content-Length');
let receivedLength = 0;
const chunks = [];
while (true) {
const {done, value} = await reader.read();
if (done) break;
chunks.push(value);
receivedLength += value.length;
const progress = (receivedLength / contentLength) * 100;
console.log(`Downloaded: ${progress.toFixed(2)}%`);
}
// Combine chunks
const blob = new Blob(chunks);
return blob;
}
Just using native browser features.
Browser Support: All modern browsers.
What it replaces: Axios progress tracking, XMLHttpRequest with progress events, download progress libraries.
13. Web Share API
Want users to share content? Instead of building custom share buttons for every platform, use the native share dialog.
async function share() {
if (navigator.share) {
try {
await navigator.share({
title: 'Check this out!',
text: 'This article is amazing',
url: 'https://example.com/article'
});
console.log('Shared successfully');
} catch (err) {
console.log('Share cancelled');
}
}
}
On mobile, this opens the system share sheet. On desktop, it shows the browser’s native share UI. Users can share to any app they have installed.
Browser Support: Chrome, Edge, Safari (mobile primarily, desktop support growing).
What it replaces: AddThis, ShareThis, custom share button implementations.
14. IndexedDB with Promises: Client-Side Database
For complex client-side data storage, IndexedDB is incredibly powerful. The native API is event-based, but the tiny idb library (~1.2KB) wraps it with Promises, making it way easier to use:
import { openDB } from 'idb';
const db = await openDB('my-database', 1, {
upgrade(db) {
db.createObjectStore('users', { keyPath: 'id' });
},
});
// Add data
await db.add('users', { id: 1, name: 'Alex', email: 'alex@example.com' });
// Get data
const user = await db.get('users', 1);
// Query data
const allUsers = await db.getAll('users');
Store megabytes of structured data client-side. Perfect for offline-first apps, caching, or complex web applications.
Browser Support: All modern browsers.
What it replaces: LocalForage, Dexie.js, PouchDB for client-side storage.
15. CSS has()Â Selector
This technically isn’t a JavaScript API, but it replaces so much JavaScript for conditional styling.
/* Style a card differently if it has an image */
.card:has(img) {
display: grid;
grid-template-columns: 200px 1fr;
}
/* Style form if it has errors */
form:has(.error) {
border: 2px solid red;
}
/* Style parent based on child state */
.container:has(button:hover) {
background: lightgray;
}
Before :has(), you needed JavaScript to add classes to parents based on children. Now it's pure CSS.
Browser Support: Chrome 105+, Edge 105+, Safari 15.4+, Firefox 121+. Baseline Newly Available since December 2023.
What it replaces: jQuery parent selectors, custom JavaScript for parent styling.
Final Thoughts
Browsers are becoming incredibly capable. Features that used to require libraries are now built-in, tested, and optimized by browser vendors.
The benefits are real:
- Smaller bundle sizes (often going from 50KB+ to 0KB)
- Better performance (native code is faster than JavaScript)
- No dependency maintenance (no more npm updates for security patches)
- Better accessibility (browser APIs handle it automatically)
- Future-proof (browsers maintain these APIs, not you)
Does this mean you should never use libraries? Of course not. Libraries still have their place for complex use cases, polyfills for older browsers, or features not yet available natively.
But next time you reach for a library, check if there’s a native API that does the same thing. You might be surprised how much you don’t need anymore.
Modern web development isn’t about installing packages, it’s about knowing what the platform already gives you.
Start using these native APIs today. I guarantee your bundle size will thank you.
Did you learn something good today as a developer?
Then show some love. đź‘‹
© Muhammad Usman
WordPress Developer | Website Strategist | SEO Specialist
*Don’t forget to subscribe to Developer’s Journey to show your support.

Top comments (0)