Profile
Back to NewsBack
GitHub Trending 18 min
Reader Mode
camsong/You-Dont-Need-jQuery: Examples of how to do query, style, dom, ajax, event etc like jQuery with plain javascript.

camsong/You-Dont-Need-jQuery: Examples of how to do query, style, dom, ajax, event etc like jQuery with plain javascript.

15 hours ago

You (Might) Don't Need jQuery

Frontend environments evolve rapidly nowadays and modern browsers have already implemented a great deal of DOM/BOM APIs which are good enough for production use. We don't have to learn jQuery from scratch for DOM manipulation or event handling. In the meantime, thanks to the spread of frontend libraries such as React, Angular and Vue, manipulating the DOM directly becomes anti-pattern, so that jQuery usage has never been less important. This project summarizes most of the alternatives in native JavaScript implementation to jQuery methods.

Snippets target current evergreen browsers (Chrome, Edge, Firefox, Safari). Internet Explorer is no longer supported by Microsoft, so IE-specific fallbacks have been removed. If you still need them, see the last IE-compatible version.

ℹ️ Notice:

  1. jQuery is still a great library and has many valid use cases. Don’t migrate away if you don’t want to!
  2. The alternatives are not completely equivalent in all scenarios, and it is recommended that you test it before using it.

Table of Contents

  1. Translations
  2. Query Selector
  3. CSS & Style
  4. DOM Manipulation
  5. Ajax
  6. Events
  7. Utilities
  8. Promises
  9. Animation
  10. Alternatives
  11. Browser Support

Translations

Query Selector

In place of common selectors like class, id or attribute we can use document.querySelector or document.querySelectorAll for substitution. The differences lie in:

  • document.querySelector returns the first matched element
  • document.querySelectorAll returns all matched elements as a static NodeList. It supports forEach, and can be converted to Array using Array.from(document.querySelectorAll(selector)) or any of the methods outlined in makeArray
  • If there are no elements matched, jQuery returns an empty jQuery object and document.querySelectorAll returns an empty NodeList, whereas document.querySelector returns null.
Notice: document.getElementById, document.getElementsByClassName and document.getElementsByTagName are slightly faster than querySelector, but getElementsBy return a live HTMLCollection that changes as the DOM changes. Prefer querySelector* unless you have measured a bottleneck.

  • 1.0 Query by selector
// jQuery
  $('selector');

// Native document.querySelectorAll('selector');

  • 1.1 Query by class
// jQuery
  $('.class');

// Native document.querySelectorAll('.class');

// or document.getElementsByClassName('class');

  • 1.2 Query by id
// jQuery
  $('#id');

// Native document.querySelector('#id');

// or document.getElementById('id');

  • 1.3 Query by attribute
// jQuery
  $('a[target=_blank]');

// Native document.querySelectorAll('a[target=_blank]');

  • 1.4 Query in descendants
// jQuery
  $el.find('li');

// Native el.querySelectorAll('li');

  • 1.5 Sibling/Previous/Next Elements
+ All siblings
// jQuery
    $el.siblings();

// Native [...el.parentNode.children].filter((child) => child !== el );

+ Previous sibling

// jQuery
    $el.prev();

// Native el.previousElementSibling;

+ Next sibling

// jQuery
    $el.next();

// Native el.nextElementSibling;

+ All previous siblings

// jQuery (optional filter selector)
    $el.prevAll($filter);

// Native (optional filter function) function getPreviousSiblings(elem, filter) { const sibs = []; while ((elem = elem.previousElementSibling)) { if (!filter || filter(elem)) sibs.push(elem); } return sibs; }

+ All next siblings

// jQuery (optional selector filter)
    $el.nextAll($filter);

// Native (optional filter function) function getNextSiblings(elem, filter) { const sibs = []; while ((elem = elem.nextElementSibling)) { if (!filter || filter(elem)) sibs.push(elem); } return sibs; }

An example of filter function:

function exampleFilter(elem) {
      switch (elem.nodeName.toUpperCase()) {
        case 'DIV':
          return true;
        case 'SPAN':
          return true;
        default:
          return false;
      }
    }
Return the first matched element by provided selector, traversing from current element up through its ancestors in the DOM tree.
// jQuery
  $el.closest(selector);

// Native el.closest(selector);

  • 1.7 Parents Until
Get the ancestors of each element in the current set of matched elements, up to but not including the element matched by the selector, DOM node, or jQuery object.
// jQuery
  $el.parentsUntil(selector, filter);

// Native function parentsUntil(el, selector, filter) { const result = [];

// match start from parent el = el.parentElement; while (el && !el.matches(selector)) { if (!filter || el.matches(filter)) { result.push(el); } el = el.parentElement; } return result; }

+ Input/Textarea
// jQuery
    $('#my-input').val();

// Native document.querySelector('#my-input').value;

+ Get index of e.currentTarget between .radio

// jQuery
    $('.radio').index(e.currentTarget);

// Native [...document.querySelectorAll('.radio')].indexOf(e.currentTarget);

  • 1.9 Iframe Contents
$('iframe').contents() returns contentDocument for this specific iframe

+ Iframe contents

// jQuery
    $iframe.contents();

// Native iframe.contentDocument;

+ Iframe Query

// jQuery
    $iframe.contents().find('.css');

// Native iframe.contentDocument.querySelectorAll('.css');

// jQuery
  $('body');

// Native document.body;

  • 1.11 Attribute getter and setter
+ Get an attribute
// jQuery
    $el.attr('foo');

// Native el.getAttribute('foo');

+ Set an attribute

// jQuery
    $el.attr('foo', 'bar');

// Native el.setAttribute('foo', 'bar');

+ Get a data- attribute

// jQuery
    $el.data('foo');

// Native el.dataset.foo;

// or el.getAttribute('data-foo');

  • 1.12 Selector containing string (case-sensitive)
// jQuery
    $("selector:contains('text')");

// Native function contains(selector, text) { const elements = document.querySelectorAll(selector); return Array.from(elements).filter((element) => element.textContent.includes(text) ); }

⬆ back to top

CSS & Style

+ Get style
// jQuery
    $el.css('color');

// Native // NOTE: returns the resolved value, e.g. 'rgb(255, 0, 17)' rather than '#f01' getComputedStyle(el).color;

+ Set style

// jQuery
    $el.css({ color: '#f01' });

// Native el.style.color = '#f01';

+ Set multiple styles

// jQuery
    $el.css({ color: '#f01', 'border-color': '#f02' });

// Native Object.assign(el.style, { color: '#f01', borderColor: '#f02' });

+ Add class

// jQuery
    $el.addClass(className);

// Native el.classList.add(className);

+ Remove class

// jQuery
    $el.removeClass(className);

// Native el.classList.remove(className);

+ has class

// jQuery
    $el.hasClass(className);

// Native el.classList.contains(className);

+ Toggle class

// jQuery
    $el.toggleClass(className);

// Native el.classList.toggle(className);

  • 2.2 Width & Height
Width and Height are theoretically identical, take Height as example:

+ Window height

// jQuery
    $(window).height();

// without scrollbar, behaves like jQuery window.document.documentElement.clientHeight;

// with scrollbar window.innerHeight;

+ Document height

// jQuery
    $(document).height();

// Native const body = document.body; const html = document.documentElement; const height = Math.max( body.offsetHeight, body.scrollHeight, html.clientHeight, html.offsetHeight, html.scrollHeight );

+ Element height

// jQuery
    $el.height();

// Native function getHeight(el) { const styles = window.getComputedStyle(el); const height = el.offsetHeight; const borderTopWidth = parseFloat(styles.borderTopWidth); const borderBottomWidth = parseFloat(styles.borderBottomWidth); const paddingTop = parseFloat(styles.paddingTop); const paddingBottom = parseFloat(styles.paddingBottom); return height - borderBottomWidth - borderTopWidth - paddingTop - paddingBottom; }

// accurate to integer (when border-box, it's height - border; when content-box, it's height + padding) el.clientHeight;

// accurate to decimal (when border-box, it's height; when content-box, it's height + padding + border) el.getBoundingClientRect().height;

  • 2.3 Position & Offset
+ Position

Get the current coordinates of the element relative to the offset parent.

// jQuery
    $el.position();

// Native const position = { left: el.offsetLeft, top: el.offsetTop };

+ Offset

Get the current coordinates of the element relative to the document.

// jQuery
    $el.offset();

// Native function getOffset (el) { const box = el.getBoundingClientRect();

return { top: box.top + window.scrollY, left: box.left + window.scrollX }; }

Get the current vertical position of the scroll bar for the element.
// jQuery
  $(window).scrollTop();

// Native window.scrollY;

⬆ back to top

DOM Manipulation

Remove the element from the DOM.
// jQuery
  $el.remove();

// Native el.remove();

+ Get text

Get the combined text contents of the element including their descendants,

// jQuery
    $el.text();

// Native el.textContent;

+ Set text

Set the content of the element to the specified text.

// jQuery
    $el.text(string);

// Native el.textContent = string;

+ Get HTML
// jQuery
    $el.html();

// Native el.innerHTML;

+ Set HTML

// jQuery
    $el.html(htmlString);

// Native el.innerHTML = htmlString;

Append child element after the last child of parent element
// jQuery: unified syntax for DOMString and Node objects
  $parent.append(newEl | '<div id="container">Hello World</div>');

// Native (Element or text): strings are inserted as plain text, not parsed as HTML parent.append(newEl | 'Hello World');

// Native (HTML string) parent.insertAdjacentHTML('beforeend', '<div id="container">Hello World</div>');

// jQuery: unified syntax for DOMString and Node objects
  $parent.prepend(newEl | '<div id="container">Hello World</div>');

// Native (Element or text): strings are inserted as plain text, not parsed as HTML parent.prepend(newEl | 'Hello World');

// Native (HTML string) parent.insertAdjacentHTML('afterbegin', '<div id="container">Hello World</div>');

  • 3.6 insertBefore
Insert a new node before the selected elements
// jQuery
  $newEl.insertBefore(selector);

const el = document.querySelector(selector);

// Native (Element) el.before(newEl);

// Native (HTML string) el.insertAdjacentHTML('beforebegin', '<div id="container">Hello World</div>');

  • 3.7 insertAfter
Insert a new node after the selected elements
// jQuery
  $newEl.insertAfter(selector);

const el = document.querySelector(selector);

// Native (Element) el.after(newEl);

// Native (HTML string) el.insertAdjacentHTML('afterend', '<div id="container">Hello World</div>');

Return true if it matches the query selector
// jQuery - Notice is also works with a function, an existing jQuery object or a DOM element, which are not of concern here
  $el.is(selector);

// Native el.matches(selector);

Create a deep copy of an element: it copies the matched element as well as all of its descendant elements and text nodes.

// jQuery. Pass true to also copy event handlers and data.
  $el.clone();

// Native. Pass true for a deep copy; event listeners are never copied. el.cloneNode(true);

Remove all child nodes
// jQuery
  $el.empty();

// Native el.replaceChildren();

Wrap an HTML structure around each element
// jQuery
  $('.inner').wrap('<div class="wrapper"></div>');

// Native document.querySelectorAll('.inner').forEach((el) => { const wrapper = document.createElement('div'); wrapper.className = 'wrapper'; el.before(wrapper); wrapper.append(el); });

Remove the parents of the set of matched elements from the DOM
// jQuery
  $('.inner').unwrap();

// Native new Set([...document.querySelectorAll('.inner')].map((el) => el.parentElement)) .forEach((parent) => { if (parent !== document.body) { parent.replaceWith(...parent.childNodes); } });

Replace each element in the set of matched elements with the provided new content
// jQuery
  $('.inner').replaceWith('<div class="outer"></div>');

// Native document.querySelectorAll('.inner').forEach((el) => { const outer = document.createElement('div'); outer.className = 'outer'; el.replaceWith(outer); });

Parse a string into HTML/SVG/XML
// jQuery
  $(<ol>
    <li>a</li>
    <li>b</li>
  </ol>
  <ol>
    <li>c</li>
    <li>d</li>
  </ol>);

// Native function parse(html) { const template = document.createElement('template'); template.innerHTML = html; return template.content; }

parse(<ol> <li>a</li> <li>b</li> </ol> <ol> <li>c</li> <li>d</li> </ol>);

⬆ back to top

Ajax

Fetch API is the standard replacement for XMLHttpRequest and works in all modern browsers. Unlike $.ajax, fetch does not reject on HTTP error status such as 404 or 500; check response.ok yourself. For JSONP, try fetch-jsonp.

  • 4.0 Request JSON
// jQuery
  $.getJSON(url).done(handleData).fail(handleError);

// Native fetch(url) .then((response) => { if (!response.ok) { throw new Error(HTTP ${response.status}); } return response.json(); }) .then(handleData) .catch(handleError);

// jQuery
  $.ajax({
    url,
    method: 'POST',
    contentType: 'application/json',
    data: JSON.stringify(data),
  });

// Native fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), });

// jQuery
  const jqXHR = $.ajax({ url, timeout: 5000 });
  jqXHR.abort();

// Native const controller = new AbortController(); fetch(url, { signal: controller.signal }); controller.abort();

// Native (timeout) fetch(url, { signal: AbortSignal.timeout(5000) });

  • 4.1 Load data from the server and place the returned HTML into the matched element.
// jQuery
  $(selector).load(url, completeCallback)

// Native fetch(url) .then((response) => response.text()) .then((html) => { document.querySelector(selector).innerHTML = html; }) .then(completeCallback);

⬆ back to top

Events

  • 5.0 Document ready by DOMContentLoaded
// jQuery
  $(document).ready(eventHandler);

// Native // Check if the DOMContentLoaded has already been completed if (document.readyState !== 'loading') { eventHandler(); } else { document.addEventListener('DOMContentLoaded', eventHandler); }

// Or load your script with <script defer> or <script type="module">, // which runs after the document has been parsed.

  • 5.1 Bind an event with on
// jQuery
  $el.on(eventName, eventHandler);

// Native el.addEventListener(eventName, eventHandler);

  • 5.1.1 Bind an event once with one
// jQuery
  $el.one(eventName, eventHandler);

// Native el.addEventListener(eventName, eventHandler, { once: true });

// jQuery
  $el.on(eventName, selector, eventHandler);

// Native el.addEventListener(eventName, (event) => { const target = event.target.closest(selector); if (target && el.contains(target)) { eventHandler.call(target, event); } });

  • 5.2 Unbind an event with off
// jQuery
  $el.off(eventName, eventHandler);

// Native el.removeEventListener(eventName, eventHandler);

// Native: remove several listeners at once, like jQuery namespaces const controller = new AbortController(); el.addEventListener('click', onClick, { signal: controller.signal }); el.addEventListener('keydown', onKeydown, { signal: controller.signal }); controller.abort();

// jQuery
  $(el).trigger('custom-event', {key1: 'data'});

// Native. jQuery events bubble, native ones don't unless bubbles: true. // Read the data from event.detail in the handler. const event = new CustomEvent('custom-event', { bubbles: true, cancelable: true, detail: { key1: 'data' }, });

el.dispatchEvent(event);

⬆ back to top

Utilities

Most of jQuery utilities are also found in the native API. Other advanced functions could be chosen from better utilities libraries, focusing on consistency and performance. Lodash and es-toolkit are recommended replacements.

  • 6.1 Basic utilities
+ isArray

Determine whether the argument is an array.

// jQuery
  $.isArray(array);

// Native Array.isArray(array);

+ isWindow

Determine whether the argument is a window.

// jQuery
  $.isWindow(obj);

// Native function isWindow(obj) { return obj != null && obj === obj.window; }

+ inArray

Search for a specified value within an array and return its index (or -1 if not found).

// jQuery
  $.inArray(item, array);

// Native array.indexOf(item);

Test if a specified value is found within an array.

// jQuery
  $.inArray(item, array) > -1;

// Native array.indexOf(item) > -1;

// ES6-way array.includes(item);

+ isNumeric

Determine if the argument passed is numerical. Use typeof to decide the type or the type example for better accuracy.

// jQuery
  $.isNumeric(item);

// Native function isNumeric(n) { return !isNaN(parseFloat(n)) && isFinite(n); }

+ isFunction

Determine if the argument passed is a JavaScript function object.

// jQuery
  $.isFunction(item);

// Native function isFunction(item) { if (typeof item === 'function') { return true; } var type = Object.prototype.toString.call(item); return type === '[object Function]' || type === '[object GeneratorFunction]'; }

+ isEmptyObject

Check to see if an object is empty (contains no enumerable properties).

// jQuery
  $.isEmptyObject(obj);

// Native function isEmptyObject(obj) { return Object.keys(obj).length === 0; }

+ isPlainObject

Check to see if an object is a plain object (created using “{}” or “new Object”).

// jQuery
  $.isPlainObject(obj);

// Native function isPlainObject(obj) { if (Object.prototype.toString.call(obj) !== '[object Object]') { return false; }

const proto = Object.getPrototypeOf(obj); return proto === null || proto === Object.prototype; }

+ extend

Merge the contents of two or more objects together into a new object, without modifying either argument. Like $.extend without deep, Object.assign and spread only make a shallow copy.

// jQuery
  $.extend({}, object1, object2);

// Native Object.assign({}, object1, object2);

// Native (spread) ({ ...object1, ...object2 });

Deep copy a single object:

// jQuery
  $.extend(true, {}, object);

// Native. Functions and DOM nodes cannot be cloned structuredClone(object);

+ trim

Remove the white-space from the beginning and end of a string.

// jQuery
  $.trim(string);

// Native string.trim();

+ map

Translate all items in an array or object to new array of items.

// jQuery
  $.map(array, (value, index) => {
  });

// Native array.map((value, index) => { });

+ each

A generic iterator function, which can be used to seamlessly iterate over both objects and arrays.

// jQuery (return false to break)
  $.each(array, (index, value) => {
  });

// Native (use for...of or some if you need to break early) array.forEach((value, index) => { });

// Native, for objects Object.entries(obj).forEach(([key, value]) => { });

+ grep

Finds the elements of an array which satisfy a filter function.

// jQuery
  $.grep(array, (value, index) => {
  });

// Native array.filter((value, index) => { });

+ type

Determine the internal JavaScript [Class] of an object.

// jQuery
  $.type(obj);

// Native function type(item) { const reTypeOf = /(?:^\[object\s(.*?)\]$)/; return Object.prototype.toString.call(item) .replace(reTypeOf, '$1') .toLowerCase(); }

+ merge

Merge the contents of two arrays together into the first array.

// jQuery, modifies array1, doesn't remove duplicate items
  $.merge(array1, array2);

// Native, modifies array1, doesn't remove duplicate items array1.push(...array2);

// Native, returns a new array, doesn't remove duplicate items function merge(...args) { return [].concat(...args); }

// Set version, returns a new array, does remove duplicate items function merge(...args) { return Array.from(new Set([].concat(...args))); }

+ now

Return a number representing the current time.

// jQuery
  $.now();

// Native Date.now();

+ proxy

Takes a function and returns a new one that will always have a particular context.

// jQuery
  $.proxy(fn, context);

// Native fn.bind(context);

+ makeArray

Convert an array-like object into a true JavaScript array.

// jQuery
  $.makeArray(arrayLike);

// Native Array.from(arrayLike);

// ES6-way: spread operator [...arrayLike];

Check to see if a DOM element is a descendant of another DOM element.
// jQuery
  $.contains(el, child);

// Native el !== child && el.contains(child);

Execute some JavaScript code globally.
// jQuery
  $.globalEval(code);

// Native function globalEval(code) { const script = document.createElement('script'); script.text = code;

document.head.appendChild(script).parentNode.removeChild(script); }

// Use eval, but context of eval is current, context of $.globalEval is global. eval(code);

+ parseHTML

Parses a string into an array of DOM nodes.

// jQuery
  $.parseHTML(htmlString);

// Native function parseHTML(string) { const context = document.implementation.createHTMLDocument();

// Set the base href for the created document so any parsed elements with URLs // are based on the document's URL const base = context.createElement('base'); base.href = document.location.href; context.head.appendChild(base);

context.body.innerHTML = string; return Array.from(context.body.childNodes); }

Check if an element exists in the DOM
// jQuery
  if ($('selector').length) {
    // exists
  }

// Native if (document.querySelector('selector')) { // exists }

⬆ back to top

Promises

A promise represents the eventual result of an asynchronous operation. jQuery has its own way to handle promises. Native JavaScript implements a thin and minimal API to handle promises according to the Promises/A+ specification, and async/await makes them read like synchronous code.

  • 7.1 done, fail, always
done is called when promise is resolved, fail is called when promise is rejected, always is called when promise is either resolved or rejected.
// jQuery
  $promise.done(doneCallback).fail(failCallback).always(alwaysCallback)

// Native promise.then(doneCallback, failCallback).finally(alwaysCallback);

// Native (async/await) try { doneCallback(await promise); } catch (error) { failCallback(error); } finally { alwaysCallback(); }

when is used to handle multiple promises. It will resolve when all promises are resolved, and reject if either one is rejected.
// jQuery
  $.when($promise1, $promise2).done((promise1Result, promise2Result) => {
  });

// Native Promise.all([promise1, promise2]).then(([promise1Result, promise2Result]) => {});

// Native (async/await) const [promise1Result, promise2Result] = await Promise.all([promise1, promise2]);

Deferred is a way to create promises.
// jQuery
  function asyncFunc() {
    const defer = new $.Deferred();
    setTimeout(() => {
      if(true) {
        defer.resolve('some_value_computed_asynchronously');
      } else {
        defer.reject('failed');
      }
    }, 1000);

return defer.promise(); }

// Native function asyncFunc() { return new Promise((resolve, reject) => { setTimeout(() => { if (true) { resolve('some_value_computed_asynchronously'); } else { reject('failed'); } }, 1000); }); }

// Deferred way function asyncFunc() { const { promise, resolve, reject } = Promise.withResolvers(); setTimeout(() => { if (true) { resolve('some_value_computed_asynchronously'); } else { reject('failed'); } }, 1000);

return promise; }

⬆ back to top

Animation

The Web Animations API (el.animate()) is the closest native match to jQuery effects: it takes a duration in milliseconds, runs off the main thread where possible, and returns an Animation whose finished promise resolves when it ends.

  • 8.1 Show & Hide
// jQuery
  $el.show();
  $el.hide();

// Native el.style.display = ''; // or 'block', 'inline', ... if a stylesheet hides it el.style.display = 'none';

// Native (if the element is not styled with display elsewhere) el.hidden = false; el.hidden = true;

Display or hide the element.
// jQuery
  $el.toggle();

// Native if (getComputedStyle(el).display === 'none') { el.style.display = ''; // or 'block', 'inline', ... } else { el.style.display = 'none'; }

  • 8.3 FadeIn & FadeOut
// jQuery
  $el.fadeIn(3000);
  $el.fadeOut(3000);

// Native fadeIn function fadeIn(el, ms = 400) { el.style.display = ''; return el.animate([{ opacity: 0 }, { opacity: 1 }], ms).finished; }

// Native fadeOut function fadeOut(el, ms = 400) { return el.animate([{ opacity: 1 }, { opacity: 0 }], ms).finished.then(() => { el.style.display = 'none'; }); }

Adjust the opacity of the element.
// jQuery
  $el.fadeTo('slow',0.15);
  // Native ('slow' equals 600 milliseconds in jQuery)
  el.animate([{ opacity: 0.15 }], { duration: 600, fill: 'forwards' });
Display or hide the element by animating their opacity.
// jQuery
  $el.fadeToggle();

// Native, using fadeIn and fadeOut from 8.3 if (getComputedStyle(el).display === 'none') { fadeIn(el); } else { fadeOut(el); }

  • 8.6 SlideUp & SlideDown
// jQuery
  $el.slideUp();
  $el.slideDown();

// Native slideUp function slideUp(el, ms = 400) { el.style.overflow = 'hidden'; return el.animate([{ height: ${el.offsetHeight}px }, { height: '0px' }], ms).finished.then(() => { el.style.display = 'none'; el.style.overflow = ''; }); }

// Native slideDown function slideDown(el, ms = 400) { el.style.display = ''; el.style.overflow = 'hidden'; return el.animate([{ height: '0px' }, { height: ${el.scrollHeight}px }], ms).finished.then(() => { el.style.overflow = ''; }); }

  • 8.7 SlideToggle
Display or hide the element with a sliding motion.
// jQuery
  $el.slideToggle();

// Native, using slideUp and slideDown from 8.6 if (getComputedStyle(el).display === 'none') { slideDown(el); } else { slideUp(el); }

Perform a custom animation of a set of CSS properties.
// jQuery
  $el.animate({ params }, speed);

// Native (speed in milliseconds) el.animate([params], { duration: speed, fill: 'forwards' });

Alternatives

  • You Might Not Need jQuery - Examples of how to do common event, element, ajax etc with plain javascript.
  • MDN Web Docs - Reference for every DOM API used here.
  • Baseline - Check which web platform features are safe to use across browsers.

Browser Support

![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![Safari][safari-image] | ![Opera][opera-image] --- | --- | --- | --- | --- | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ |

A few snippets use newer APIs: Promise.withResolvers() (2024), el.replaceChildren() (2020) and AbortSignal.timeout() (2022). Check Baseline if you support older browsers.

License

MIT

[chrome-image]: https://raw.github.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png [firefox-image]: https://raw.github.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png [edge-image]: https://raw.github.com/alrra/browser-logos/master/src/edge/edge_48x48.png [opera-image]: https://raw.github.com/alrra/browser-logos/master/src/opera/opera_48x48.png [safari-image]: https://raw.github.com/alrra/browser-logos/master/src/safari/safari_48x48.png

Chat with me