Hide menu
Valid for: HT21

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:

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 the button’s aria-expanded attribute should be true. When its content div is not visible, the button’s aria-expanded value should be set to false.
  • 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 the id of the content div it controls the visibility of
    • aria-labelledby: this attribute is set on a content div and its value is the id of the button 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, the hidden attribute is often used when creating accessible UI components rather than just setting display: none. Just setting display: 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’s aria-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’s aria-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 tabs
    • tab: this element is a selectable tab
    • tabpanel: this is a panel with the content associated with a tab
  • State The currently selected tab should have the attribute aria-selected set to true. All other tabs should have aria-selected set to false.
  • Relationship
    • aria-controls: this attribute is set on a tab and its value is the id of the panel it controls the visibility of
    • aria-labelledby: this attribute is set on a element with the tabpanel role and its value is the id of the tab 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 attribute aria-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