Converting jQuery Blog Post Component To Vanilla JS

I have a simple blog component that is written in jQuery. I would like to convert it to plain JavaScript as part of my effort to completely remove jQuery from my portfolio website.

export default {
  textboxHeight: '',
  init() {
    $('.post-difficulty .header-info').click(this.toggle.bind(this));

    // get initial box height and add it as variable
    let $textbox = $('.post-difficulty .difficulty-information');
    this.textboxHeight = $textbox.outerHeight();
    $textbox.css({
      'height': 0,
      'padding': 0,
    });
  },
  toggle() {
    let isOut = $('.post-difficulty').attr('aria-toggled') == 'true';
    if(isOut) {
      $('.post-difficulty').attr('aria-toggled', 'false');
      $('.post-difficulty .toggle-icon').removeClass('fa-caret-up');
      $('.post-difficulty .toggle-icon').addClass('fa-caret-down');

      // toggle and style the information back on
      $('.post-difficulty .difficulty-information').css({
        'opacity': 0,
        'height': 0,
        'padding': 0,
      })
    }
    else {
      $('.post-difficulty').attr('aria-toggled', 'true');
      $('.post-difficulty .toggle-icon').removeClass('fa-caret-down');
      $('.post-difficulty .toggle-icon').addClass('fa-caret-up');

      // toggle and style the information back on
      $('.post-difficulty .difficulty-information').css({
        'opacity': 1,
        'height': this.textboxHeight,
        'padding': '15px',
      })
    }
  },
}

Here’s what the code does in order.

init() on .header-info click, call the toggle method. Get the initial textbox height and store it as a variable on the current object. Set height and padding to 0 to set the initial state of hidden on the toggleable portion.

toggle() if aria-toggled is true, we can assume the component is toggled and expanded. If it’s out, set aria-toggled to the opposite value and update the toggle icon. Set the css of the toggleable portion to be hidden again. If aria-toggled is false, we need to expand the component. Do this by setting the aria-toggled prop to true, update the icon class and set the appropriate values, and set the textboxHeight.

Let’s get to refactoring this!

export default {
  textboxHeight: '',
  init() {
    if (!document.querySelectorAll('.post-difficulty').length) return

    document.querySelector('.post-difficulty .header-info').addEventListener(
      'click',
      this.toggle.bind(this)
    )

    // get initial box height and add it as variable
    const $textbox = document.querySelector('.post-difficulty .difficulty-information')
    this.textboxHeight = $textbox.clientHeight
    $textbox.style.height = 0
    $textbox.style.padding = 0
  },
  toggle() {
    const $difficulty = document.querySelector('.post-difficulty')
    const $icon = document.querySelector('.post-difficulty .toggle-icon')
    const $difficultyInformation = document.querySelector('.post-difficulty .difficulty-information')

    if($difficulty.getAttribute('aria-toggled') === 'true') {
      $difficulty.setAttribute('aria-toggled', 'false')
      $icon.classList.remove('fa-caret-up')
      $icon.classList.add('fa-caret-down')

      // toggle and style the information back on
      $difficultyInformation.style.opacity = 0
      $difficultyInformation.style.height = 0
      $difficultyInformation.style.padding = 0
    }
    else {
      $difficulty.setAttribute('aria-toggled', 'true')
      $icon.classList.remove('fa-caret-down')
      $icon.classList.add('fa-caret-up')

      // toggle and style the information back on
      $difficultyInformation.style.opacity = 1
      $difficultyInformation.style.height = this.textboxHeight + 'px'
      $difficultyInformation.style.padding = '15px'
    }
  },
}

Refactoring this was very straightforward and the resulting code isn’t noticeably longer. I opted to declare style selectors as variables because document.querySelector can get a bit lengthy (and were often referenced multiple times anyways).

Comments