JSFiddle - React, Tailwind, and code Playground

HTML

<article class="layout">
  <div class="shop">
    <h1>Our articles</h1>
    <p>Articles will be added to favorite list ordered by last added.</p>
    <ul>
      <li id="22">
        <span>Article 1 (id: 22)</span>
        <button class="shop-item__favorite-button" data-add-to-favorite="22" data-favorite-title="Meredith dress">
          <span class="sr-only"
                data-favorite="Add to my favorites"
                data-favorite-added="Remove from my favorites"></span>
        </button>
      </li>
      <li id="23">
        <span>Article 2 (id: 23)</span>
        <button class="shop-item__favorite-button" data-add-to-favorite="23" data-favorite-title="Meredith Skirt">
          <span class="sr-only"
                data-favorite="Add to my favorites"
                data-favorite-added="Remove from my favorites"></span>
        </button>
      </li>
      <li id="24">
        <span>Article 3 (id: 24)</span>
        <button class="shop-item__favorite-button" data-add-to-favorite="24" data-favorite-title="Josephine short">
          <span class="sr-only"
                data-favorite="Add to my favorites"
                data-favorite-added="Remove from my favorites"></span>
        </button>
      </li>
      <li id="25">
        <span>Article 4 (id: 25)</span>
        <button class="shop-item__favorite-button" data-add-to-favorite="25" data-favorite-title="Josephine shirt">
          <span class="sr-only"
                data-favorite="Add to my favorites"
                data-favorite-added="Remove from my favorites"></span>
        </button>
      </li>
      
      
      <li><span>To force scroll</span></li>
      <li><span>To force scroll</span></li>
      <li><span>To force scroll</span></li>
      <li><span>To force scroll</span></li>
      <li><span>To force scroll</span></li>
      <li><span>To force scroll</span></li>
      <li><span>To force scroll</span></li>
      <li><span>To force scroll</span></li>
      <li><span>To force...

JavaScript

const favoriteButtonAttr = 'data-add-to-favorite';
const isFavorite = 'data-is-favorite';
const listSelector = '[data-my-favorites]';

class FavoritesList {
  constructor () {
    this.storageName = 'favoritesList';
    this.list = this.initList();
  }
  
  initList () {
    if (window.localStorage.getItem(this.storageName)) { 
      // todo: repetitive parse?
      const list = JSON.parse(window.localStorage.getItem(this.storageName));
      updateHtmlList(list);
      return list;
    } else {   
      return [];
    }
  }
  
  initButton(button) {
    const id = parseInt(button.getAttribute(favoriteButtonAttr));
    
    button.addEventListener('click', (event) => {
      const button = event.target;
      !inArray(id, this.list) ? this.list.push(id) : removeFromArray(id, this.list);
      setState(id, this.list);
      this.updateList();
    })
    
    function setState (id, list) {
      return button.toggleAttribute(isFavorite, inArray(id, list));
    }
    
    setState(id, this.list);
    return button;
  }
  
  updateList() {
    setLocalStorage(this.storageName, this.list);
    updateHtmlList(this.list); 
  }
}

function scrollTo(animate, to, duration, extraOffset, doneCallback) {
  // When should we finish?
  var finishAt = Date.now() + duration;
  
  // Start
  requestAnimationFrame(tick);

  function tick() {
    // How many frames left? (60fps = 16.6ms per frame)
    var framesLeft = (finishAt - Date.now()) / 16.6;
    
    // How far do we have to go?
    var distance = to.getBoundingClientRect().top + (extraOffset || 0);
    if (distance == 0) {
      // Done (this shouldn't happen, belt & braces)
      return;
    }
    
    // Adjust by one frame's worth
    if (framesLeft <= 1) {
      // Last call
      animate.scrollTop += distance;
      
      if (doneCallback)
      	doneCallback(to);
    } else {
      // Not the last, adjust and schedule next
      var dir = distance < 0 ? -1 : 1;
      animate.scrollTop += dir * Math.max(1, dir *...