DEV Community

Cover image for Web APIs That Replace Entire Libraries
Muhammad Usman
Muhammad Usman

Posted on • Originally published at pixicstudio.Medium

Web APIs That Replace Entire Libraries

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();
  });
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode
/* Customize specific elements */
.hero-image {
  view-transition-name: hero;
}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode
<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>
Enter fullscreen mode Exit fullscreen mode

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-index battles!)

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);
}
Enter fullscreen mode Exit fullscreen mode
/* Style the backdrop */
[popover]::backdrop {
  background: rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(4px);
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode
@container (min-width: 400px) {
  .card {
    display: grid;
    grid-template-columns: 1fr 2fr;
  }
}
Enter fullscreen mode Exit fullscreen mode

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');
Enter fullscreen mode Exit fullscreen mode
const animation = element.animate([
  { transform: 'translateX(0px)', opacity: 1 },
  { transform: 'translateX(300px)', opacity: 0 }
], {
  duration: 1000,
  easing: 'ease-in-out',
  fill: 'forwards'
});
Enter fullscreen mode Exit fullscreen mode
// Control it programmatically
animation.pause();
animation.play();
animation.reverse();
animation.currentTime = 500; // Jump to middle
Enter fullscreen mode Exit fullscreen mode

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);
    }
  });
});
Enter fullscreen mode Exit fullscreen mode
// Watch elements
document.querySelectorAll('.lazy-load').forEach(el => {
  observer.observe(el);
});
Enter fullscreen mode Exit fullscreen mode

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
  });
});
Enter fullscreen mode Exit fullscreen mode
observer.observe(document.querySelector('.responsive-element'));
Enter fullscreen mode Exit fullscreen mode

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);
  }
}
Enter fullscreen mode Exit fullscreen mode
// 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);
  }
}
Enter fullscreen mode Exit fullscreen mode

It even works with images and other data types!

// Copy image
async function copyImage(blob) {
  await navigator.clipboard.write([
    new ClipboardItem({ 'image/png': blob })
  ]);
}
Enter fullscreen mode Exit fullscreen mode

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');
Enter fullscreen mode Exit fullscreen mode
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!');
});
Enter fullscreen mode Exit fullscreen mode
// Or convert to object
const data = Object.fromEntries(formData.entries());
Enter fullscreen mode Exit fullscreen mode

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));
Enter fullscreen mode Exit fullscreen mode
// Retrieve it
const savedUser = JSON.parse(localStorage.getItem('user'));
Enter fullscreen mode Exit fullscreen mode
// Session-only data
sessionStorage.setItem('tempData', 'This disappears when tab closes');
Enter fullscreen mode Exit fullscreen mode

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');
    }
  );
}
Enter fullscreen mode Exit fullscreen mode

You can even watch position changes for live tracking:

const watchId = navigator.geolocation.watchPosition(
  (position) => {
    updateMapMarker(position.coords);
  }
);
Enter fullscreen mode Exit fullscreen mode
// Stop watching later
navigator.geolocation.clearWatch(watchId);
Enter fullscreen mode Exit fullscreen mode

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);
    }
  });
});
Enter fullscreen mode Exit fullscreen mode
observer.observe(document.body, {
  childList: true,
  subtree: true,
  attributes: true,
  characterData: true
});
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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');
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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';
Enter fullscreen mode Exit fullscreen mode
const db = await openDB('my-database', 1, {
  upgrade(db) {
    db.createObjectStore('users', { keyPath: 'id' });
  },
});
Enter fullscreen mode Exit fullscreen mode
// Add data
await db.add('users', { id: 1, name: 'Alex', email: 'alex@example.com' });
Enter fullscreen mode Exit fullscreen mode
// Get data
const user = await db.get('users', 1);
Enter fullscreen mode Exit fullscreen mode
// Query data
const allUsers = await db.getAll('users');
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode
/* Style form if it has errors */
form:has(.error) {
  border: 2px solid red;
}
Enter fullscreen mode Exit fullscreen mode
/* Style parent based on child state */
.container:has(button:hover) {
  background: lightgray;
}
Enter fullscreen mode Exit fullscreen mode

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.
Developer's Journey

Top comments (0)