Reactive CSS Variables in a Vue Component

·

2 min read

I recently created a page that embedded a huuuuuuuge table into a fixed viewport using some simple CSS:

<template>
<div id="app">
      <div id="navbar"> NAVBAR </div>
      <div class="content-wrapper">
        <div id="header">HEADER</div>
        <div class="table-wrapper">
          <table class="table">
          <thead>
            <tr>
              <th v-for="(col, i) in columns" :key="i">{{ col }}</th>
            </tr>
          </thead>
          <tbody>
          <tr v-for="person, j in people" :key="j">
            <td>{{ person.namefirst}}</td>
            <td>{{ person.namelast }}</td>
            <td>{{ person.email }}</td>
            <td> {{ person.username }}</td>
            <td> {{ person.age }}</td>
            <td> {{ person.country}}</td>
            <td> {{ person.birthdate }}</td>
            <td>{{ person.creditcard }}</td>
            <td>{{person.password}}</td>
            <td>{{person.phone}}</td>
            <td>{{person.sex}}</td>
            <td>{{person.ssn}}</td>
            <td>{{person.url}}</td>
            <td>{{person.maritalstatus}}</td>
            <td>{{person.county}}</td>
            <td>{{person.postcode}}</td>
            <td>{{person.state}}</td>
            <td>{{person.coordinates}}</td>
            <td>{{person.city}}</td>
            <td>{{person.address}}</td>
          </tr>
          </tbody>
        </table>
        </div>
      </div>
  </div>
</template>

...

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  width: 90vw;
  margin: 0 auto;
}

  .table-wrapper {
    position: absolute;
    width: 90vw;
    overflow-x: auto;
    overflow-y: auto;
  }
</style>

This was simple enough, but I needed the horizontal scroll bar to always be pinned to the bottom of the viewport, no matter how large the table is. This presents a few problems that need to be solved in JavaScript.

First, we'll need to get the window height. This needs to be responsive in case the viewport size changes while the user is using the app. Setup an event listener in the mounted() function when the app loads:

async mounted() {
    window.addEventListener('resize', () => {
      this.windowHeight = window.innerHeight
    })

We still need more information. In order to position the table directly below the header, we'll need to know more about the header's size. (In this app, the header size could also vary.) In order to do this, we will use a JavaScript method called getBoundingClientRect. This returns an object that can tell us a lot about where an element is positioned on the page.

image.png

The header properties will be calculated after the header appears on the DOM, using a computed value:

computed: {
    headerPositionY() {
      if (!this.isLoading) {
        return document.getElementById('header').getBoundingClientRect().y
      }
      return null
    },
    headerHeight() {
      if (!this.isLoading) {
        return document.getElementById('header').getBoundingClientRect().height
      }
      return null
    },
},

Now we have enough information to calculate the table height. This is also placed in the computed values:

tableHeight() {
      if (!this.isLoading) {
        return (
          Math.round(this.windowHeight) -
          Math.round(this.headerPositionY) -
          Math.round(this.headerHeight) 
        )
      }
      return null
    },

Then, we can create another computed value to return the styles to apply to the table:

tableStyles() {
      if (!this.isLoading) {
        return `height: ${this.tableHeight}px;`
      }
      return null
    },

Apply these styles to the table wrapper:

<div class="table-wrapper" :style="tableStyles">
...

Check out the full example here: codepen.io/mkbaker/pen/jOLZYwN

Additional resources:

stackoverflow.com/questions/1480133/how-can..

developer.mozilla.org/en-US/docs/Web/API/El..

developer.mozilla.org/en-US/docs/Web/API/DO..

telerik.com/blogs/passing-variables-to-css-..

stackoverflow.com/questions/65223560/what-u..

stackoverflow.com/questions/49268659/javasc..

stackoverflow.com/questions/50490561/comput..