|
6 | 6 | import { base } from "$app/paths";
|
7 | 7 | import Code from "$lib/Code.svelte";
|
8 | 8 | import SideMenu from "$lib/SideMenu.svelte";
|
| 9 | +
|
| 10 | + const demoTableRows = [ |
| 11 | + { firstname: "Janine", lastname: "Hinde", age: 16 }, |
| 12 | + { firstname: "Henk", lastname: "de Vries", age: 8 }, |
| 13 | + { firstname: "Maria", lastname: "Lin", age: 32 }, |
| 14 | + { firstname: "John", lastname: "Doe", age: 64 }, |
| 15 | + ]; |
| 16 | +
|
| 17 | + /** @type {'firstname'|'lastname'|'age'|undefined} */ |
| 18 | + let sortColumn = undefined; |
| 19 | +
|
| 20 | + /** @type {'ascending'|'descending'} */ |
| 21 | + let sortDirection = "ascending"; |
| 22 | +
|
| 23 | + $: numeric = sortColumn === "age"; |
| 24 | +
|
| 25 | + $: sortedDemoTableRows = demoTableRows |
| 26 | + .slice() |
| 27 | + .sort( |
| 28 | + sortDirection === "ascending" |
| 29 | + ? (a, b) => ("" + a[sortColumn]).localeCompare(b[sortColumn], undefined, { numeric }) |
| 30 | + : (a, b) => ("" + b[sortColumn]).localeCompare(a[sortColumn], undefined, { numeric }), |
| 31 | + ) |
| 32 | +
|
| 33 | + const toggleSort = (column) => { |
| 34 | + if (column === sortColumn) { |
| 35 | + sortDirection = sortDirection === "ascending" ? "descending" : "ascending"; |
| 36 | + } else { |
| 37 | + sortColumn = column; |
| 38 | + sortDirection = "ascending"; |
| 39 | + } |
| 40 | + }; |
9 | 41 | </script>
|
10 | 42 |
|
11 | 43 | <svelte:head>
|
|
26 | 58 | <h1>Sorteerbare tabel</h1>
|
27 | 59 | <p>
|
28 | 60 | Om inzicht te krijgen in de data kan het behulpzaam zijn om de gebruiker de data te laten
|
29 |
| - sorteren. Bijvoorbeeld op basis van op of aflopende data. |
| 61 | + sorteren. |
30 | 62 | </p>
|
31 | 63 |
|
32 | 64 | <h2>Benodigde stappen:</h2>
|
33 | 65 | <ol>
|
34 | 66 | <li>
|
35 |
| - Voeg een <code>button</code> toe binnen de <code>th</code> om sorteerelemeent klikbaar te |
36 |
| - maken. |
| 67 | + Voeg een <code><button></code> toe binnen de <code><th></code> van elke |
| 68 | + sorteerbare kolom. |
| 69 | + <ul> |
| 70 | + <li> |
| 71 | + Voeg de <code><button></code> alleen toe aan sorteerbare kolommen. Niet elke kolom |
| 72 | + hoeft sorteerbaar te zijn. |
| 73 | + </li> |
| 74 | + <li> |
| 75 | + Plaats de tekst van de kolomkop in de <code><button></code>, zodat de hele |
| 76 | + kolomkop klikbaar is. |
| 77 | + </li> |
| 78 | + </ul> |
37 | 79 | </li>
|
38 | 80 | <li>
|
39 |
| - Voeg binnen de knop een icoon toe indien gewenst. Voor meer informatie zie: |
40 |
| - <a href="{base}/components/button-icon">Icoonknoppen</a> |
| 81 | + Voeg binnen de knop van elke sorteerbare kolom een icoon toe. Voor meer informatie zie: |
| 82 | + <a href="./icons.html">Iconen</a>. |
| 83 | + <ul> |
| 84 | + <li> |
| 85 | + Voeg <code>aria-hidden="true"</code> aan de <code><span></code> van het icoon, om |
| 86 | + te voorkomen dat het icoon in de toegankelijke naam van de knop opgenomen wordt. |
| 87 | + </li> |
| 88 | + <li> |
| 89 | + Zorg dat de gebruikte Icoonset iconen heeft voor ongesoorteerde data, oplopend |
| 90 | + gesorteerde data en aflopend gesorteerde data. |
| 91 | + </li> |
| 92 | + <li> |
| 93 | + Gebruik bij voorkeur iconen met ingevulde driehoeken, bijvoorbeeld <span |
| 94 | + class="icon icon-sortable">driehoeken omhoog en omlaag</span |
| 95 | + > |
| 96 | + voor ongesorteerd, <span class="icon icon-ascending">driehoek omhoog</span> voor |
| 97 | + oplopend gesorteerd en <span class="icon icon-descending">driehoek omlaag</span> voor |
| 98 | + aflopend gesorteerd. |
| 99 | + </li> |
| 100 | + </ul> |
41 | 101 | </li>
|
42 | 102 | <li>
|
43 |
| - Voeg <code>abbr=""</code> toe aan de <code><th></code> met een korte duidelijke omschrijving |
44 |
| - om de gebruikerservaring te verbeteren voor gebruikers die gebruik maken van een screenreader. |
| 103 | + Voeg een toelichting over de sorteerknoppen toe aan de <code><caption></code>. |
| 104 | + Bijvoorbeeld: "kolomkoppen met knoppen zijn sorteerbaar". |
| 105 | + <ul> |
| 106 | + <li> |
| 107 | + Indien gewenst kan deze tekst visueel verborgen worden met de <code |
| 108 | + >visually-hidden</code |
| 109 | + > class. |
| 110 | + </li> |
| 111 | + <li> |
| 112 | + Zorg ervoor dat er een punt of komma staat tussen de bestaande caption-tekst en deze |
| 113 | + hint-tekst. Bij gebruik van een <code>visually-hidden</code> <code><>span></code> |
| 114 | + kan bijvoorbeeld een komma toegevoegd worden voorafgaand aan de hint-tekst. |
| 115 | + </li> |
| 116 | + </ul> |
| 117 | + </li> |
| 118 | + <li> |
| 119 | + Voeg een <code>abbr=""</code> toe aan de <code><th></code> indien de tekst in de |
| 120 | + <code><th></code> |
| 121 | + erg lang is. |
| 122 | + <ul> |
| 123 | + <li> |
| 124 | + De kortere omschrijving in de <code>abbr=""</code> wordt gebruikt door screenreaders |
| 125 | + bij het voorlezen van een cel in de bijbehorende kolom. |
| 126 | + </li> |
| 127 | + </ul> |
| 128 | + </li> |
| 129 | + <li> |
| 130 | + Voeg JavaScript toe voor het dynamische gedrag van het component. De exacte |
| 131 | + implementatie is afhankelijk van de context. |
| 132 | + <ul> |
| 133 | + <li> |
| 134 | + Sorteer de inhoud van de tabel wanneer de gebruiker op één van de knoppen in de |
| 135 | + kolomkoppen klikt. |
| 136 | + </li> |
| 137 | + <li> |
| 138 | + Draai de sorteervolgorde om, wanneer de gebruiker op de knop klikt van de kolom waar |
| 139 | + op dit moment op gesorteerd wordt. |
| 140 | + </li> |
| 141 | + <li> |
| 142 | + Zorg ervoor dat elke kolomkop het juiste icoon heeft, afhankelijk van de huidige |
| 143 | + sortering van de tabel. |
| 144 | + </li> |
| 145 | + <li> |
| 146 | + Voeg <code>aria-sort="ascending"</code> / <code>aria-sort="descending"</code> toe |
| 147 | + aan de <code><th></code> van de kolom waarop gesorteerd wordt. |
| 148 | + </li> |
| 149 | + </ul> |
45 | 150 | </li>
|
46 | 151 | </ol>
|
47 | 152 |
|
48 | 153 | <h2>Aandachtspunten</h2>
|
49 | 154 | <ul>
|
50 |
| - <li>Dit element bevat momenteel geen JavaScript of logica voorbeeld.</li> |
| 155 | + <li> |
| 156 | + <strong |
| 157 | + >Het is voor dit component nodig om het dynamische gedrag zelf via JavaScript te |
| 158 | + implementeren.</strong |
| 159 | + > |
| 160 | + </li> |
| 161 | + <li>De exacte implementatie in JavaScript is afhankelijk van de context.</li> |
| 162 | + <li> |
| 163 | + De manier waarop de data gesorteerd moet worden, kan afhankelijk zijn van het soort data |
| 164 | + (bijvoorbeeld tekstueel of numeriek). Dit kan per kolom verschillen. |
| 165 | + </li> |
51 | 166 | </ul>
|
52 | 167 | </section>
|
53 | 168 |
|
54 | 169 | <section id="examples">
|
55 | 170 | <h2>Voorbeelden</h2>
|
56 | 171 | <h3>Visueel voorbeeld:</h3>
|
57 | 172 | <div class="horizontal-scroll">
|
58 |
| - <table> |
59 |
| - <caption> Tabelvoorbeeld met sorteerbare data: </caption> |
| 173 | + <table id="sortable-table-example"> |
| 174 | + <caption> |
| 175 | + Tabelvoorbeeld met sorteerbare data |
| 176 | + <span class="visually-hidden">, kolomkoppen met knoppen zijn sorteerbaar</span> |
| 177 | + </caption> |
60 | 178 | <thead>
|
61 | 179 | <tr>
|
62 |
| - <th scope="col" abbr="Ascending data"> |
63 |
| - <button title="Sort descending"> |
64 |
| - Descending <span class="icon icon-ascending"></span> |
| 180 | + <th scope="col" aria-sort={sortColumn === "firstname" ? sortDirection : undefined}> |
| 181 | + <button class="sort" on:click={() => toggleSort("firstname")}> |
| 182 | + Voornaam |
| 183 | + <span |
| 184 | + aria-hidden="true" |
| 185 | + class="icon" |
| 186 | + class:icon-sortable={sortColumn !== "firstname"} |
| 187 | + class:icon-ascending={sortColumn === "firstname" && |
| 188 | + sortDirection === "ascending"} |
| 189 | + class:icon-descending={sortColumn === "firstname" && |
| 190 | + sortDirection === "descending"} |
| 191 | + /> |
| 192 | + </button> |
| 193 | + </th> |
| 194 | + <th |
| 195 | + scope="col" |
| 196 | + abbr="Achternaam" |
| 197 | + aria-sort={sortColumn === "lastname" ? sortDirection : undefined} |
| 198 | + > |
| 199 | + <button class="sort" on:click={() => toggleSort("lastname")}> |
| 200 | + Achternaam (met tussenvoegsel) |
| 201 | + <span |
| 202 | + aria-hidden="true" |
| 203 | + class="icon" |
| 204 | + class:icon-sortable={sortColumn !== "lastname"} |
| 205 | + class:icon-ascending={sortColumn === "lastname" && |
| 206 | + sortDirection === "ascending"} |
| 207 | + class:icon-descending={sortColumn === "lastname" && |
| 208 | + sortDirection === "descending"} |
| 209 | + /> |
65 | 210 | </button>
|
66 | 211 | </th>
|
67 |
| - <th scope="col" abbr="Descending data"> |
68 |
| - <button title="Sort ascending"> |
69 |
| - Ascending <span class="icon icon-descending"></span> |
| 212 | + <th |
| 213 | + scope="col" |
| 214 | + class="number" |
| 215 | + aria-sort={sortColumn === "age" ? sortDirection : undefined} |
| 216 | + > |
| 217 | + <button class="sort" on:click={() => toggleSort("age")}> |
| 218 | + Leeftijd |
| 219 | + <span |
| 220 | + aria-hidden="true" |
| 221 | + class="icon" |
| 222 | + class:icon-sortable={sortColumn !== "age"} |
| 223 | + class:icon-ascending={sortColumn === "age" && sortDirection === "ascending"} |
| 224 | + class:icon-descending={sortColumn === "age" && sortDirection === "descending"} |
| 225 | + /> |
70 | 226 | </button>
|
71 | 227 | </th>
|
72 | 228 | </tr>
|
73 | 229 | </thead>
|
74 | 230 |
|
75 | 231 | <tbody>
|
76 |
| - <tr> |
77 |
| - <td>Lorem</td> |
78 |
| - <td>Ipsum</td> |
79 |
| - </tr> |
80 |
| - <tr> |
81 |
| - <td>Lorem</td> |
82 |
| - <td>Ipsum</td> |
83 |
| - </tr> |
| 232 | + {#each sortedDemoTableRows as row} |
| 233 | + <tr> |
| 234 | + <td>{row.firstname}</td> |
| 235 | + <td>{row.lastname}</td> |
| 236 | + <td class="number">{row.age}</td> |
| 237 | + </tr> |
| 238 | + {/each} |
84 | 239 | </tbody>
|
85 | 240 | </table>
|
86 | 241 | </div>
|
|
91 | 246 | code={`
|
92 | 247 | <div class="horizontal-scroll">
|
93 | 248 | <table>
|
94 |
| - <caption>Tabelvoorbeeld met sorteerbare data:</caption> |
| 249 | + <caption> |
| 250 | + Tabelvoorbeeld met sorteerbare data |
| 251 | + <span class="visually-hidden">, kolomkoppen met knoppen zijn sorteerbaar</span> |
| 252 | + </caption> |
95 | 253 | <thead>
|
96 | 254 | <tr>
|
97 |
| - <th scope="col" abbr="Ascending data"> |
98 |
| - <button title="Sort descending">Descending <span class="icon icon-ascending"></button> |
| 255 | + <th scope="col"> |
| 256 | + <button> |
| 257 | + Voornaam |
| 258 | + <span class="icon icon-sortable" aria-hidden="true"></span> |
| 259 | + </button> |
| 260 | + </th> |
| 261 | + <th scope="col" abbr="Achternaam"> |
| 262 | + <button> |
| 263 | + Achternaam (met tussenvoegsel) |
| 264 | + <span class="icon icon-sortable" aria-hidden="true"></span> |
| 265 | + </button> |
99 | 266 | </th>
|
100 |
| - <th scope="col" abbr="Descending data"> |
101 |
| - <button title="Sort ascending">Ascending <span class="icon icon-descending"></span></button> |
| 267 | + <th scope="col"> |
| 268 | + <button> |
| 269 | + Leeftijd |
| 270 | + <span class="icon icon-sortable" aria-hidden="true"></span> |
| 271 | + </button> |
102 | 272 | </th>
|
103 | 273 | </tr>
|
104 | 274 | </thead>
|
105 | 275 |
|
106 | 276 | <tbody>
|
107 | 277 | <tr>
|
108 |
| - <td>Lorem</td> |
109 |
| - <td>Ipsum</td> |
| 278 | + <td>Janine</td> |
| 279 | + <td>Hinde</td> |
| 280 | + <td class="number">16</td> |
| 281 | + </tr> |
| 282 | + <tr> |
| 283 | + <td>Henk</td> |
| 284 | + <td>de Vries</td> |
| 285 | + <td class="number">8</td> |
| 286 | + </tr> |
| 287 | + <tr> |
| 288 | + <td>Maria</td> |
| 289 | + <td>Lin</td> |
| 290 | + <td class="number">32</td> |
110 | 291 | </tr>
|
111 | 292 | <tr>
|
112 |
| - <td>Lorem</td> |
113 |
| - <td>Ipsum</td> |
| 293 | + <td>John</td> |
| 294 | + <td>Doe</td> |
| 295 | + <td class="number">64</td> |
114 | 296 | </tr>
|
115 | 297 | </tbody>
|
116 | 298 | </table>
|
117 | 299 | </div>
|
118 |
| -`} |
| 300 | + `} |
119 | 301 | />
|
120 | 302 | </section>
|
121 | 303 |
|
|
0 commit comments