I have a Vue app calculating a table with rowspans. The algorithm calculates the data ( and rowspans ) based on a configuration file so the application only renders the columns ( and the column order ) based on the calculated result.
Given the following sample ( Reproduction link )
<template>
<table>
<thead>
<th>City</th>
<th>Inhabitant</th>
<th>House</th>
<th>Room</th>
</thead>
<tbody>
<tr v-for="(row, rowIndex) in tableMatrix" :key="rowIndex">
<template v-for="(cell, columnIndex) in row" :key="columnIndex">
<td v-if="cell.isCoveredByPreviousCell" style="display: none" />
<td v-else :rowspan="cell.rowspan ?? 1">
<template v-if="cell.content">
{{ cell.content }}
</template>
</td>
</template>
</tr>
</tbody>
</table>
</template>
<script setup lang="ts">
import { ref, Ref } from 'vue';
interface Cell { isCoveredByPreviousCell: boolean; rowspan: number; content?: string; }
type TableMatrix = Cell[][];
const tableMatrix: Ref<TableMatrix> = ref([
[
{ isCoveredByPreviousCell: false, rowspan: 5, content: "City 1" },
{ isCoveredByPreviousCell: false, rowspan: 4, content: "Inhabitant 1" },
{ isCoveredByPreviousCell: false, rowspan: 3, content: "House 1" },
{ isCoveredByPreviousCell: false, content: "Room 1" },
],
[
{ isCoveredByPreviousCell: true },
{ isCoveredByPreviousCell: true },
{ isCoveredByPreviousCell: true },
{ isCoveredByPreviousCell: false, content: "Room 2" },
],
[
{ isCoveredByPreviousCell: true },
{ isCoveredByPreviousCell: true },
{ isCoveredByPreviousCell: true },
{ isCoveredByPreviousCell: false, content: "Room 3" },
],
[
{ isCoveredByPreviousCell: true },
{ isCoveredByPreviousCell: true },
{ isCoveredByPreviousCell: false, content: "House 2" },
{ isCoveredByPreviousCell: false, content: "Room 1" },
],
[
{ isCoveredByPreviousCell: true },
{ isCoveredByPreviousCell: false, content: "Inhabitant 2" },
{ isCoveredByPreviousCell: false, content: "House 3" },
{ isCoveredByPreviousCell: false, content: "Room 1" },
]
])
</script>
<style>
table, th, td { border-collapse: collapse; border: 1px solid black; }
</style>
I get the following ( correct ) output
It’s quite hard to identify a single "line", I’m looking for a way to make this more clear. A zebra striped table won’t work for the table design. Maybe I need to add "dividing" rows with a fixed height and a different background color. Or increase the border bottom width of row cells.
I tried to add tr { border-bottom: 5px solid black; }
( reproduction link ) but then I get the following output
I also tried to add a dividing row ( reproduction link )
<tr>
<template v-for="(cell, columnIndex) in row" :key="columnIndex">
<td style="background: red">divider</td>
</template>
</tr>
but get this result
Do you have any ideas?
6
Answers
I think that it’s messy, both visually and in the code, to have it implemented with rowspans. This is because you want two cells on top of each other to be in the same row, but that’s not how it’s implemented, so any solution that makes them appear to be in the same row will be messy
This is a matter of opinion, but I think that you should put those stacked cells in the same table row, then use CSS to put one piece of information above the other in the same cell. Then you can use the
tr { border-bottom: 5px solid black; }
to get the result that you want.An implementation of my comment. First with a blurred green zebra striping:
Then with blurred colored bottom borders on the background table. I tend to like this one better.
thing you are wanting to have like zebra strips tabe
you should have something in corresponding to every cell like you have city 2, inhabitant 1 and house 1 and in room there is some data as well but in the first row there only is on td in that row there is not other td corresponding to it and now even if you want to have that zebra kinda of table then the styling will only occur in the corresponding td like the room 1 will only have a color because there is no other td corresponding to it
your code also seems a bit messy using the rowspan in js like it can be done through the html as well One of the main thing in the coding is that to keep your code as short as possible
and if you want it to be like zebra striped here’s the code
Not really a code answer, more a frame challenge:
Must it be rows? Instead you can use arrows to point from div to div (example code)
This aproach is very similar to what Google does in its Cloud Platform, where they have to solve the same issue you have. Of course this is not the most pretty drawing, its an example. You could have straight lines with 90deg turns, or everything the same colour and/or dotted.
If you wrap your current text in a span with an border and use the tables vertical align, you are very close to the example above "only" needing to connect the dots.
I think the issue is that you don’t really have lines or rows anymore, but rather nested tiles, which is why zebra stripes won’t work. I think in this case, it makes more sense to highlight these tiles and their nesting level. You can do this by adjust the borders to the level, i.e. use a thick border between cities, use a thin border between rooms:
Adjusting the vertical borders gives you these ⊢ shapes, which outline the tiles more clearly. Add some colors for a more intuitive distinction between structure and content:
Doubling the size of the borders makes the structure even more apparent, but you need to check if it works with the rest of your page:
To figure out the top border width of a row, you just have to find the index of the first data cell:
You can set it as a class on each row.
Here it is in the playground
The problem
OP wants the table’s primary rows (the most tall ones) to be clearly wisible
Here’s the OP’s image provided in comment:
https://i.imgur.com/Vt6JouO.png
The solution
This is easy to implement by adding a top border for those rows
playground