Assignment 4
The fourth and final assignment in this course consists of three exercises.
Submit your completed assignment before the deadline. Submission instructions can be found on the main assignment page.
Learning outcomes
After this lab assignment, you should have gained knowledge about the following:
- How to dispatch synthetic events
- How to write the JavaScript code and CSS to make custom UI components
- How ARIA attributes are used
Assignment points
Exercises 1 and 2 have optional tasks.
- 1 point: Complete all required tasks.
- 2 points: Complete all required tasks and one optional task.
General requirements
Create a folder the assignment and a sub-folder for each exercise.
Exercise 1 - Toggle Widget
Required task
In this exercise your task is to write the JavaScript and CSS for a toggle widget. The prefix widget-
is used for all the widget related classes and files to lower the possibility of a naming conclict.
There are prepared files for this assignment: a4e1.zip
These files contain a web page that uses the toggle widget, and the directory widget-toggle
where you will be adding the CSS and JavaScript files needed by the toggle widget.
Visuals
a4e1.html
should look something like this when you have created the CSS for the toggle widget.
Below is an image of what it should look like after you have toggled widget 2 and 4.
ARIA attributes
The two relevant ARIA attributes for the toggle widget are the role
and the aria-pressed
attributes. The widget should have role="button"
as it functions as a two state button. The attribute aria-pressed
should be set as "false"
if the button is in its “off”-state, and set to “true” when the button is in its “on”-state.
HTML
In a4e1.html
you can see the div
elements that are supposed to turn into toggle widgets. Add code to widget-toggle/widget-toggle.js
that “transforms” all the elements with the class widget-toggle
in to interactive toggle widgets.
<div class="widget-toggle" role="button" aria-pressed="false"></div>
Behavior
Please refer to the examples introduced during lecture 4 for an example of how to structure your JavaScript code.
Implement the ability for toggling the color of the widget between white and green. When the widget is white, its value should be 0
. I.e. console.log((toggleWidget.value)
should print out 0
. The value when showing green should be 1
.
Also change the value of the attribute aria-pressed
accordingly (more info: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/button_role).
Fire input events
The widget should also fire input
events when the user clicks it that bubble. See the lecture slides, and the following two pages for more info:
- https://developer.mozilla.org/en-US/docs/Web/Events/Creating_and_triggering_events
- https://developer.mozilla.org/en-US/docs/Web/API/Event/Event
Optional task 1
Allow the user to specify two images to be used to show the state of the widget:
<div class="widget-toggle">
<img src="green.png">
<img src="red.png">
</div>
When widget-toggle.js
is run with the optional task implemented, green.png
should be shown initially. When the user clicks on the widget, red.png
should be shown. Clicking again switches the images.
You can use these image URL:s if you do not want to use your own images:
Exercise 2 - Accordion Widget
Required task
Your goal of in the second exercise is to create accordion widgets. The prefix widget-
is used for all the widget related classes and files to lower the possibility of a naming conclict.
There are prepared files for this assignment: a4e2.zip
These files contain a web page that uses the accordion widgets, and the directory widget-accordion
where you will be adding the CSS and JavaScript needed by the accordion widget.
Visuals
a4e2.html
should look something like this when you have created the CSS for the accordion widget.
Tip: You can use the CSS below to add different triangles when the accordian is opened and closed.
.widget-accordion button::before {
content: "▶︎ ";
}
.widget-accordion button[aria-expanded="true"]::before {
content: "▼︎ ";
}
ARIA attributes
- Role The element containing the content of an accordion panel has
role="region"
- State When a button’s content
div
is visible, the value of thebutton
’saria-expanded
attribute should betrue
. When its contentdiv
is not visible, the button’saria-expanded
value should be set tofalse
. - Relationship You are not required to apply these attributes for the assignment.
aria-controls
: this attribute is set on a button and and its value is theid
of the contentdiv
it controls the visibility ofaria-labelledby
: this attribute is set on a contentdiv
and its value is theid
of thebutton
it belongs to.
- Misc An element with the
hidden
attribute will not be visible in the browser, nor will it be read by any assistive technologies. Because of this, thehidden
attribute is often used when creating accessible UI components rather than just settingdisplay: none
. Just settingdisplay: none
will hide it from seeing users, but it may still be read by some assistive tools.
HTML
The idea here, is to let the user write only what is necessary from a content author’s perspective. Here is the HTML that is the user is required to write.
<div class="widget-accordion">
<h2>Accordion 1 title</h2>
<div><p>Content for Accordion 1<p></div>
<h2>Accordion 2 title</h2>
<div><p>Content for Accordion 2<p></div>
<h2>Accordion 3 title</h2>
<div><p>Content for Accordion 3<p></div>
</div>
When your code has run, the above HTML should be transformed into the HTML below and make the code below an interactive tab widget. This is just an example. You should transform the actual HTML content inside the provided HTML file.
<div class="widget-accordion">
<ul>
<li>
<button aria-expanded="false">Accordion 1 title</button>
<div role="region" hidden=""><p>Content for Accordion 1</p></div>
</li>
<li>
<button aria-expanded="false">Accordion 2 title</button>
<div role="region" hidden=""><p>Content for Accordion 2</p></div>
</li>
<li>
<button aria-expanded="false">Accordion 3 title</button>
<div role="region" hidden=""><p>Content for Accordion 3</p></div>
</li>
</ul>
</div>
Important: Some methods and properties, e.g. Element.children
and Document.getElementsByClassName()
return a live HTMLCollection
. “Live” means that any changes to the DOM will be immediately reflected in the HTMLCollection
. If you intend to move any elements in the HTMLCollection
to a new place in the DOM, do NOT do this from inside of a e.g. a for
-loop where you are using indexes. Instead, copy the elements to an array and loop through the array: let myElements = Array.from(myHTMLCollection)
and loop over the array.
If you try to loop over a live HTMLCollection of e.g. the children of a node and move any of the children to another place in the DOM, the HTMLCollection will shrink and you will have a smaller HTMLCollection than you initially had.
Note: You cannot change the tagName
of a DOM node, e.g. you cannot change a h2
to a button
. Instead you have to create a new button
element, then copy the .innerHTML
and destroy the h2
element (use Element.remove()
).
Behavior
- If an unexpanded accordion title is clicked, its content is revealed (remove the
hidden
attribute) and the value of the title’saria-expanded
attribute is set to"true"
. - If a expanded accordion title is clicked, its content is hidden (add the
hidden
attribute) and the value of the title’saria-expanded
attribute is set to"false"
. - There are no dependencies between accordions, i.e. any number of accordions may be opened or closed at the same time.
Optional Task 2
- Animate the accordions opening and closing using anime.js
Exercise 3 - Tabs Widget
Required task
You final task for this assignment is to create a widget for tabs. The prefix widget-
is used for all the widget related classes and files to lower the possibility of a naming conclict.
There are prepared files for this assignment: a4e3.zip
These files contain a web page that uses the tabs widgets, and the directory widget-tabs
where you will be adding the CSS and JavaScript needed by the tabs widget.
Visuals
a4e3.html
should look something like this when you have created the CSS for the tabs widget.
ARIA attributes
The tab widget has a number of ARIA attributes associated with it.
- Roles In the tab widget, the attribute
role
can have following values:tablist
: this element contains tabstab
: this element is a selectable tabtabpanel
: this is a panel with the content associated with a tab
- State The currently selected tab should have the attribute
aria-selected
set totrue
. All other tabs should havearia-selected
set tofalse
. - Relationship
aria-controls
: this attribute is set on atab
and its value is theid
of the panel it controls the visibility ofaria-labelledby
: this attribute is set on a element with thetabpanel
role and its value is theid
of thetab
it belongs to.
- Misc The
hidden
attribute is set on tabpanels that are not visible
HTML
The idea here, similar to the accordion widget, is to let the user write only what is necessary from a content author’s perspective. Here is the HTML that is the user is required to write.
<div class="widget-tabs">
<h2>Tab 1 title</h2>
<div><p>Content for Tab 1<p></div>
<h2>Tab 2 title</h2>
<div><p>Content for Tab 1<p></div>
<h2>Tab 3 title</h2>
<div><p>Content for Tab 1<p></div>
</div>
When your code is run, it should transform the above html into the html below, and make the code below an interactive tab widget.
When your code has run, the above HTML should be transformed into the HTML below and make the code below an interactive tab widget. This is just an example. You should transform the actual HTML content inside the provided HTML file.
<div class="widget-tabs">
<div role="tablist">
<button id="tab-1" role="tab" aria-selected="true" aria-controls="panel-1">Tab 1</button>
<button id="tab-2" role="tab" aria-selected="false" aria-controls="panel-2">Tab 2</button>
<button id="tab-3" role="tab" aria-selected="false" aria-controls="panel-3">Tab 3</button>
</div>
<div id="panel-1" role="tabpanel" aria-labeledby="tab-1">
<p>Content for Tab 1<p>
</div>
<div id="panel-2" role="tabpanel" aria-labelledby="tab-2" hidden>
<p>Content for Tab 2<p>
</div>
<div id="panel-3" role="tabpanel" aria-labelledby="tab-3" hidden>
<p>Content for Tab 3<p>
</div>
</div>
Add classes according to your needs. However, remember that you can also use the attribute selector; e.g. the selector button[aria-selected="true"]
will target the selected tab.
Behavior
- Exactly one tab per tab-widget and its associated tabpanel should be selected/not hidden at any time.
- Clicking a tab reveals the tabpanel it controls and hides the any previously shown tabpanel.
- The attribute
aria-selected
of the clicked tab should be set to"true"
. The value of the attributearia-selected
of all other tabs should be set to"false"
. - The selected tab should have a different visual style from the non-selected tabs.
- It should only be possible for one tab to selected and visible at the same time.
Page contact: Jody Foo
Last update: 2021-12-06