I have a "sortable" table where the header of the currently sorted column displays an icon:
The sort icon is to be displayed at the end of the text (i.e., we are supporting LTR/RTL). I'm currently using display:flex
. However, if the table width shrinks and the column header text begins to wrap, I run into ambiguous states where it's not clear which column is sorted:
Instead I would like to meet the following requirements:
For example:
I've been experimenting with a bunch of different combinations of display: inline/inline-block/flex/grid
, position
, ::before/::after
, and even float
(!) but can't get the desired behavior. Here is my current code demonstrating the problem:
.table {
border-collapse: collapse;
width: 100%;
}
.thead {
border-bottom: 3px solid #d0d3d3;
}
.thead .tr {
vertical-align: bottom;
}
.button {
padding: 1rem;
text-align: start;
font-family: Arial, "noto sans", sans-serif;
font-size: 0.875rem;
border: 0;
background-color: transparent;
width: 100%;
display: flex;
align-items: flex-end;
font-weight: bold;
line-height: 1.4;
}
.sort {
width: 1.25rem;
height: 1.25rem;
}
<table class="table">
<thead class="thead">
<tr class="tr">
<th class="th">
<button class="button">
Age
<span class="sort"></span>
</button>
</th>
<th class="th">
<button class="button">
Favorite Food
<span class="sort"></span>
</button>
</th>
<th class="th" aria-sort="ascending">
<button class="button">
Favorite Color
<span class="sort">
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" role="presentation" style="width: 1.25rem; height: 1.25rem;"> <path d="M11.4709 4.2136C11.7638 3.92071 12.2386 3.92071 12.5315 4.2136L17.1277 8.8098C17.4206 9.10269 17.4206 9.57756 17.1277 9.87046C16.8348 10.1633 16.3599 10.1633 16.0671 9.87046L12.7512 6.55459V19.25C12.7512 19.6642 12.4154 20 12.0012 20C11.587 20 11.2512 19.6642 11.2512 19.25V6.55459L7.93533 9.87046C7.64244 10.1633 7.16756 10.1633 6.87467 9.87046C6.58178 9.57756 6.58178 9.10269 6.87467 8.8098L11.4709 4.2136Z"> </path></svg>
</span>
</button>
</th>
<th class="th">
<button class="button">
Likes Neil Diamond?
<span class="sort"></span>
</button>
</th>
</tr>
</thead>
</table>
Any ideas on how to accomplish this UI? This probably has little to do with the table or button stuff. Really I need Thing A
"tightly" bottom/end aligned to Thing B
(of a flexible width and which can have wrapped text) but Thing A
can't wrap onto a line of its own.
I've tried messing with the flex
values but any combination either makes the text wrap prematurely or not soon enough.
To align things in the inline direction, use the properties which begin with justify- . Use justify-content to distribute space between grid tracks, and justify-items or justify-self to align items inside their grid area in the inline direction.
To left justify in CSS, use the CSS rule text-align: left.
Think you need JS for this. Here's an answer that should meet all conditions except 5.
const debounce = fn => {
let frame;
return (...params) => {
if (frame) {
cancelAnimationFrame(frame);
}
frame = requestAnimationFrame(() => {
fn(...params);
});
};
};
const text = [...document.querySelectorAll(".text")];
const iconWidth = "1.25rem";
const positionIcon = () => {
if (!text) return;
text.forEach(t => {
const width = t.getBoundingClientRect().width;
const icon = t.nextElementSibling;
if (!icon) return;
icon.style.left = `calc(${width}px + ${iconWidth})`;
});
};
positionIcon();
window.addEventListener("resize", debounce(positionIcon));
.table {
border-collapse: collapse;
width: 100%;
}
.thead {
border-bottom: 3px solid #d0d3d3;
}
.thead .tr {
vertical-align: bottom;
}
.button {
padding: 1rem;
text-align: start;
font-family: Arial, "noto sans", sans-serif;
font-size: 0.875rem;
border: 0;
background-color: transparent;
width: 100%;
font-weight: bold;
line-height: 1.4;
position: relative;
}
.sort {
width: 1.25rem;
height: 1.25rem;
position: absolute;
bottom: 1rem;
left: 100%; /* no js fallback */
}
.sort svg {
height: 1.25rem;
width: 1.25rem;
}
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<svg id="arrow" viewBox="0 0 24 24" role="presentation"> <path d="M11.4709 4.2136C11.7638 3.92071 12.2386 3.92071 12.5315 4.2136L17.1277 8.8098C17.4206 9.10269 17.4206 9.57756 17.1277 9.87046C16.8348 10.1633 16.3599 10.1633 16.0671 9.87046L12.7512 6.55459V19.25C12.7512 19.6642 12.4154 20 12.0012 20C11.587 20 11.2512 19.6642 11.2512 19.25V6.55459L7.93533 9.87046C7.64244 10.1633 7.16756 10.1633 6.87467 9.87046C6.58178 9.57756 6.58178 9.10269 6.87467 8.8098L11.4709 4.2136Z"> </path></svg>
</svg>
<table class="table">
<thead class="thead">
<tr class="tr">
<th class="th">
<button class="button">
<span class="text">Age</span>
<span class="sort">
<svg>
<use xlink:href="#arrow">
</svg>
</span>
</button>
</th>
<th class="th">
<button class="button">
<span class="text">Favourite Food</span>
<span class="sort">
<svg>
<use xlink:href="#arrow">
</svg>
</span>
</button>
</th>
<th class="th" aria-sort="ascending">
<button class="button">
<span class="text">Favorite Color</span>
<span class="sort">
<svg>
<use xlink:href="#arrow">
</svg>
</span>
</button>
</th>
<th class="th">
<button class="button">
<span class="text">Likes Neil Diamond?</span>
<span class="sort">
<svg>
<use xlink:href="#arrow">
</svg>
</span>
</button>
</th>
</tr>
</thead>
</table>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With