Grid layout with vue.js

Girish Venkatachalam
3 min readMay 6, 2024

--

grid child and parent with vue.js

What is vue.js?

Vue.js is an SPA framework written by Evan You and team. It is simple and you can create vue projects with full tooling or just include the vue script in header and get a simple app.

Either way you need to understand the syntax. We have seen several vue projects before, all of the use the v-for and some conditionals and reactivity , refs and lifecycle hooks.

vue.js requires you to master these at a very minimum.

How to setup sample project?

$ npm create vue@latest
$ cd <project>
$ yarn
$ yarn serve

Code sample and demo

We are setting up a simple grid layout. We have a child and parent and how communication happens between two components. I will let the code do the talking.

GridParent.vue

<!--
An example of creating a reusable grid component and using it with
external data.
-->
<script setup>
import DemoGrid from './GridChild.vue'
import { ref } from 'vue'
const searchQuery = ref('')
const gridColumns = ['name', 'power']
const gridData = [
{ name: 'Chuck Norris', power: Infinity },
{ name: 'Bruce Lee', power: 9000 },
{ name: 'Jackie Chan', power: 7000 },
{ name: 'Jet Li', power: 8000 }
]
</script>
<template>
<form id="search">
Search <input name="query" v-model="searchQuery">
</form>
<DemoGrid
:data="gridData"
:columns="gridColumns"
:filter-key="searchQuery">
</DemoGrid>
</template>

GridChild.vue

<script setup>
import { ref, computed } from 'vue'
const props = defineProps({
data: Array,
columns: Array,
filterKey: String
})
const sortKey = ref('')
const sortOrders = ref(
props.columns.reduce((o, key) => ((o[key] = 1), o), {})
)
const filteredData = computed(() => {
let { data, filterKey } = props
if (filterKey) {
filterKey = filterKey.toLowerCase()
data = data.filter((row) => {
return Object.keys(row).some((key) => {
return String(row[key]).toLowerCase().indexOf(filterKey) > -1
})
})
}
const key = sortKey.value
if (key) {
const order = sortOrders.value[key]
data = data.slice().sort((a, b) => {
a = a[key]
b = b[key]
return (a === b ? 0 : a > b ? 1 : -1) * order
})
}
return data
})
function sortBy(key) {
sortKey.value = key
sortOrders.value[key] *= -1
}
function capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1)
}
</script>
<template>
<table v-if="filteredData.length">
<thead>
<tr>
<th v-for="key in columns" :key="key" @click="sortBy(key)"
:class="{ active: sortKey == key }">
{{ capitalize(key) }}
<span class="arrow" :class="sortOrders[key] > 0 ? 'asc' :
'dsc'">
</span>
</th>
</tr>
</thead>
<tbody>
<tr v-for="entry in filteredData" :key="entry">
<td v-for="key in columns" :key="key">
{{entry[key]}}
</td>
</tr>
</tbody>
</table>
<p v-else>No matches found.</p>
</template>
<style>
table {
border: 2px solid #42b983;
border-radius: 3px;
background-color: #fff;
}
th {
background-color: #42b983;
color: rgba(255, 255, 255, 0.66);
cursor: pointer;
user-select: none;
}
td {
background-color: #f9f9f9;
}
th,
td {
min-width: 120px;
padding: 10px 20px;
}
th.active {
color: #fff;
}
th.active .arrow {
opacity: 1;
}
.arrow {
display: inline-block;
vertical-align: middle;
width: 0;
height: 0;
margin-left: 5px;
opacity: 0.66;
}
.arrow.asc {
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-bottom: 4px solid #fff;
}
.arrow.dsc {
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 4px solid #fff;
}
</style>

main.js

import { createApp } from 'vue'
import GridParent from './GridParent.vue';
createApp(GridParent).mount('#app')

Conclusion

Using vue.js is fun and we have seen spreadsheets and similar work in svelte as well. It is fun to port code between these two frameworks. It could be a fun project to try.

For this one at least you can try changing the styling and see how you can make sense.

--

--

Girish Venkatachalam

Author of Photoveda image editor Chrome plugin, SDK, API. Vim fanatic. Solopreneur for 19 years. Love coding in Python(Jupyter notebook). Linux fanatic.