- Table Of Contents
- About The Project
- Requirements
- My Process
- Built with
- What I Learned
- Additional Features
- Resources
- Author
- Acknowledgments
This project is a simple single-page responsive design which takes data from the Random User Generator API and builds a table which can sorted by the column headers with a mouse and/or keyboard.
This project is a simple responsive web page which takes data from the Random User Generator API and builds an accessible table which can sorted by the column headers with a click
of a mouse and/or enter/space
key.
Read the API documentation to find out more about the response values and how to test the API. Notice the URL I am using for this project is requesting 10 users (results=10
) from the United States (nat=us
): https://randomuser.me/api/?nat=us&results=10
Click Here to see the random user properties available
gender
: (string) gender (male/female),name
: (object) contains name datatitle
: (string) title (Mr., Ms, etc)first
: (string) first namelast
: (string) last name
location
: (object) contains location datastreet
: (string) street number and namecity
: (string)citystate
: (string) statepostcode
: (string) zip/postal code
coordinates
: (object) contains coordinates datalatitude
: (string) latitudelongitude
: (string) longitude
timezone
: (object) contains time zone dataoffset
: (string) timezone offsetdescription
: (string) time zone
email
: (string) email addresslogin
: (object) contains login datauuid
: (string) unique user id,username
: (string) usernamepassword
: (string) passwordsalt
: (string) salt hashmd5
: (string) md5 hashsha1
: (string) sha1 hashsha256
: (string) sha256 hash
dob
: (object) contains age datadate
: (timestamp) date of birthage
: (number) age of person
registered
: (object) contains registration datadate
: (timestamp) registrationage
: (number) age of membership
phone
: (string) phone numbercell
: (string) cell phone numberid
: (object) contains id dataname
: (string) id namevalue
: (string) id value
picture
: (object) contains picture datalarge
: (string) URL of large imagemedium
: (string) URL of medium imagethumbnail
: (string) URL of thumbnail image
nat
: (string) nationality
- Use the result a from the Random User Generator API
- Use HTML, CSS and Javascript to show the data in a readable table (including mobile view)
- All columns should have the ability to be sorted by mouse and/or keyboard
As a user, I should:
- See a
loading
state when the page initially renders - See an HTML
table
when the data is successfully loaded - See all the HTML
table
data inmobile
andtablet
view - See an
error
message within the table body if it is not working - Be able to
click
on a column, see a visual cue that the column has been selected - Be able to use the following keyboard keys to control:
- Direction Keys
-
tab
,shift+tab
-
↑
,↓
,←
,→
-
w
,s
,a
,d
-
home
,end
-
- Sorting
-
enter
,space
-
- Direction Keys
As a developer, I should
- Implement 2 examples of caching in order to increase the overall performance of the page
- Use the BEM (Block Element Modifier) naming convention for CSS class names
- Use accessibility principles to ensure the page is accessible by the browser and any assistive technologies connected as well (i.e screen readers)
Since the requirements were fetching API data and rendering a table, I approached it the following way:
Create an index.html
file and fill it with the elements that were not going to be changing like the <header>
and root <table>
element. Add BEM (Block Element Modifier) naming convention for adding class names (i.e c-header
and c-table
).
Create a script.js
and write out the following functions:
- fetch data from the Random User API
- render the contents of the
<table>
element (<th>
,<tr>
,<td>
, etc.) with the Random User API data
- render the contents of the
- Create Event Listeners:
- Click
<button>
in Column header (<th>
)- when clicked, it sorts the table ascending/descending order and rerenders the page with the results
- Keydown
left arrow
,up arrow
,a
,w
- Move the focus to the previous HTML element with a
tabindex
attribute
- Move the focus to the previous HTML element with a
right arrow
,down arrow
,d
,s
- Move the focus to the next HTML element with a
tabindex
attribute
- Move the focus to the next HTML element with a
home
- Move the focus to the first HTML element with a
tabindex
attribute
- Move the focus to the first HTML element with a
end
- Move the focus to the last HTML element with a
tabindex
attribute
- Move the focus to the last HTML element with a
- Click
- Add Normalize.css to reset the CSS browser defaults
- Create a
style.css
and add styles to:
- Header -
.c-header
- Header Title -
.c-header__title
- Header Subtitle -
.c-header__subtitle
- Header Title -
- Table -
c-table
- table header -
c-table__head
- header cell (th) -
.c-table__th
- button -
.c-table__button
- button -
- header cell (th) -
- table body -
c-table__body
- table row (tr)
.c-table__tr
- table data (td)
.c-table__td
- table data (td)
- table row (tr)
- table header -
- Loading Screen -
.l-loading-container
.is-loading
- Animations
move
keyframe animationgrow
keyframe animation
- Mobile view styling
@media screen and (max-width: 768px)
- Semantic HTML5
- CSS3
- Normalize.css
- CSS Animation (loading screen)
- CSS custom properties
- BEM naming convention
- ES6 JavaScript
- Async/Await
- Fetch
- Closures/Memoization
After reviewing the Deque University Sortable Table Example, it looks like making a <table>
with the appropriate nested table elements (<thead>
, <tbody>
<th>
, <tr>
,<td>
).
Here is a skeleton example with the recommended ARIA attributes:
<table role="grid" aria-readonly="true">
<thead>
<tr role="row">
<th role="columnheader" scope="col">col 1<th>
<th role="columnheader" scope="col">col 2<th>
<th role="columnheader" scope="col">col 3<th>
</tr>
</thead>
<tbody>
<tr role="row">
<th scope="row" role="rowheader">data 1</th>
<td role="gridcell">data 2</td>
<td role="gridcell">data 3</td>
<tr>
</tbody>
</table>
For assistive technology, It is preferred that the selected <th>
have the following attribute to let the reader know which order the column is sorted:
aria-sort="ascending"
aria-sort="descending"
NOTE: some ARIA attributes may be built into the semantic table elements. I found conflicting information and decided to add the ARIA attributes to ensure they are available to any assistive technologies.
In most API fetching demos, the API call is made as the page is rendered. I decided to use SessionStorage
to store the initial API call data. After the initial fetch, the table will pull the data directly from SessionStorage
.
Once the user closes out the window tab, the data from session storage is removed. Below is the snippet where I added session storage logic:
sortable-table/assets/js/script.js
Lines 342 to 360 in 891f3f9
I had to demonstrate memoization for a few technical interviews recently. I wanted to implement memoization so that the table did not need to run a sort function every time the column button is clicked.
So I initially create a cache within the event listener function and return a function that will be used when the column button is clicked.
sortable-table/assets/js/script.js
Lines 71 to 81 in 891f3f9
Win the return function, we will try to access the cache to see if cache[
${order}${column}]
(example cache['ascending1']
for column 1 in ascending order). if it does not exist, we will perform the sort.
sortable-table/assets/js/script.js
Lines 95 to 149 in 891f3f9
After the sort is performed, we will store it in the cache
object for future reference.
sortable-table/assets/js/script.js
Line 146 in 891f3f9
we will call saveToCache
and name the returning function sortByTableColumn
sortable-table/assets/js/script.js
Line 16 in f95667b
We then call sortByTableColumn
in the click listener. Notice I create an event listener on the document and add a conditional for make sure the button with a class js-column-button
is the only element that the sorting function will work.
sortable-table/assets/js/script.js
Lines 327 to 337 in 891f3f9
sortable-table/assets/js/script.js
Lines 366 to 367 in 891f3f9
This Kevin Powell YouTube video on CSS custom properties really helped me better understand how to use these properties. Here is an example. I created 5 custom properties in my body
selector so I can use the custom properties within all nested elements
sortable-table/assets/css/style.css
Lines 2 to 13 in 3f0fa71
Now I have a custom property called --main-text-color
that stores the hex code of black (#111111
). But since my button is going to be blue, I would like my text color to be white (#ffffff
). Rather than create another custom property, I can overwrite (or locally scope) the property within a selector and use the same property name like so:
sortable-table/assets/css/style.css
Lines 81 to 87 in 3f0fa71
Now the text color within my button will be white (#ffffff
)
After reading the namespace section of this Smashing Magazine article on mistakes to avoid using BEM (Block, Element, Modifier), I decided to apply the same BEM prefix namespacing as in the Smashing Magazine article. Below is the table that shows the prefix description and examples from the article.
— David Berner
Type Prefix Examples Description Component c- c-card
c-checklistForm the backbone of an application and contain all of the cosmetics for a standalone component. Layout module l- l-grid
l-containerThese modules have no cosmetics and are purely used to position c- components and structure an application’s layout. Helpers h- h-show
h-hideThese utility classes have a single function, often using !important to boost their specificity. (Commonly used for positioning or visibility.) States is-
has-is-visible
has-loadedIndicate different states that a c- component can have. JavaScript hooks js- js-tab-switcher These indicate that JavaScript behavior is attached to a component. No styles should be associated with them; they are purely used to enable easier manipulation with script.
Source of namespacing: Harry Robert - More Transparent UI Code with Namespaces
As a result I used the following block class names:
- Components -
c-header
,c-table
- Elements -
c-header__title
,c-table__td
- Layout -
.l-table-container
,.l-loading-container
- States -
is-loading
,has-error
- Pagination for multiple pages of results
- In tablet/mobile view, add tab functionality to focus on each card full of data
- Add an input to search on the table and highlight
- Web AIM - Creating accessible tables
- MDN - HTML table advanced features and accessibility
- Deque University - Sortable table example
- W3 - Sortable table example
- Codepen - David Miller - Responsive table example
- MDN Docs - table-layout
- LogRocket- CSS animated page loading
- Smashing Magazine - David Berner - Battling BEM CSS: 10 Common Problems And How To Avoid Them
- CSS Wizardry - Harry Robert - More Transparent UI Code with Namespaces
- Go Make Things - JavaScript Event Delegation - This helped me better understand how event delegation works in JavaScript.
- Go Make Things - Inject text and HTML with JavaScript - This article helped me as a reference.
- Random User API Documentation Here is the documentation for the Random User API for reference.
- JavaScript.info - Optional Chaining
- MDN - switch statement
- Go Make Things - Chris Ferndinandi - JavaScript format date helper function
- Mastering JS - Date object
- freeCodeCamp - Understanding JavaScript Memoization
- Website - adamabundis.xyz
- GitHub - @abuna1985
- Twitter - @adamabundis
- @sw-yx @techieEliot @rayning0 and @amhayslip pushing the dev community (including myself) to learn and grow in public.
- @kevin-powell for making me smarter about CSS
- @cferdinandi for making me smarter about JavaScript.