Attributes

Attributes were briefly discussed in Overview of HTML; it's time for a deep dive.
Attributes are what make HTML so powerful. Attributes are space-separated names and name/value pairs appearing in the opening tag,
providing information about and functionality for the element.
{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/17yQeLEUX6s88IbDJreQ.png", alt="The opening tag, attributes, and closing tag, labelled on an HTML element.", width="800", height="210" %}
Attributes define the behavior, linkages, and functionality of elements. Some attributes are global, meaning they can appear
within any element's opening tag. Other attributes apply to several elements but not all, while other attributes are element-specific,
relevant only to a single element. In HTML, all attributes except boolean, and to some extent enumerated attributes, require a value.
If an attribute value includes a space or special characters, the value must be quoted. For this reason, and for improved legibility,
quoting is always recommended.
While HTML is not case-sensitive, some attribute values are. Values that are part of the HTML specification are case-insensitive.
Strings values that are defined, such as class and id names, are case-sensitive. If an attribute value is case-sensitive in HTML,
it is case-sensitive when used as part of an attribute selector in CSS and in JavaScript; otherwise, it's not.
<!-- the type attribute is case insensitive: these are equivalent -->
<input type="text">
<input type="TeXt">
<!-- the id attribute is case sensitive: they are not equivalent -->
<div id="myId">
<div id="MyID">
Boolean attributes
If a boolean attribute is present, it is always true. Boolean attributes include 
autofocus, 
inert, 
checked, 
disabled,
required, 
reversed, 
allowfullscreen, 
default, 
loop, 
autoplay, 
controls, 
muted, 
readonly, 
multiple, and 
selected.
If one (or more) of these attributes is present, the element is disabled, required, readonly, etc. If not present, it isn't.
Boolean values can either be omitted, set to an empty string, or be the name of the attribute; but the value doesn't have to actually
be set to the string 
true. All values, including 
true, 
false, and 
😀, while invalid, will resolve to true.
These three tags are equivalent:
<input required>
<input required="">
<input required="required">
If the attribute value is false, omit the attribute. If the attribute is true, include the attribute but don't provide a value.
For example, 
required="required" is not a valid value in HTML; but as 
required is boolean, invalid values resolve to true.
But as invalid enumerated attributes don't necessarily resolve to the same value as missing values, it is easier to get into the
habit of omitting values than it is to remember which attributes are boolean versus enumerated and potentially provide an invalid value.
When toggling between true and false, add and remove the attribute altogether with JavaScript rather than toggling the value.
const myMedia = document.getElementById("mediaFile");
myMedia.removeAttribute("muted");
myMedia.setAttribute("muted");
Note that in XML languages, like SVG, all attributes need to include a value, including boolean attributes.
Enumerated attributes
Enumerated attributes are sometimes confused with boolean attributes. They are HTML attributes that have a limited set of predefined valid values.
Like boolean attributes, they have a default value if the attribute is present but the value is missing. For example, if you include 
<style contenteditable>,
it defaults to 
<style contenteditable="true">.
Unlike boolean attributes, though, omitting the attribute doesn't mean it's false; a present attribute with a missing value
isn't necessarily true; and the default for invalid values isn't necessarily the same as a null string. Continuing the example,
contenteditable defaults to 
inherit if missing or invalid, and can be explicitly set to 
false.
The default value depends on the attribute. Unlike boolean values, attributes aren't automatically "true" if present. If you
include 
<style contenteditable="false">, the element is not editable. If the value is invalid, such as 
<style contenteditable="😀">,
or, surprisingly, 
<style contenteditable="contenteditable">, the value is invalid and defaults to 
inherit.
In most cases with enumerated attributes, missing and invalid values are the same. For example, if the 
type attribute on an 
<input>
is missing, present but without a value, or has an invalid value, it defaults to 
text. While this behavior is common, it is not a rule.
Because of this, it's important to know which attributes are boolean versus enumerated; omit values if possible so you don't get them wrong, and look up the value as needed.
Global attributes
Global attributes are attributes that can be set on any HTML element, including elements in the 
<head>. There are more than
30 global attributes. While these can all, in theory, be added to any HTML element, some global attributes have no effect
when set on some elements; for example, setting 
hidden on a 
<meta> as meta content is not displayed.
id
The global attribute 
id is used to define a unique identifier for an element. It serves many purposes, including:
The target of a link's fragment identifier.
Identifying an element for scripting.
Associating a form element with its label.
Providing a label or description for assistive technologies.
Targeting styles with (high specificity or as attribute selectors) in CSS.
The 
id value is a string with no spaces. If it contains a space, the document won't break, but you'll have to target the
id with escape characters in your HTML, CSS, and JS. All other characters are valid. An 
id value can be 
😀 or 
.class,
but is not a good idea. To make programming easier for your current and future self, make the 
id's first character a letter,
and use only ASCII letters, digits, 
_, and 
-. It's good practice to come up with an 
id naming convention and then stick to it,
as 
id values are case-sensitive.
The
id should be unique to the document. The layout of your page probably won't break if an 
id is used more than once,
but your JavaScript, links, and element interactions may not act as expected.
Link fragment identifier
The navigation bar includes four links. We will cover the link element later, but for now, realize links are not restricted
to HTTP-based URLs; they can be fragment identifiers to sections of the page in the current document (or in other documents).
On the machine learning workshop site, the navigation bar in the page header includes four links:
{% Codepen {
user: 'web-dot-dev',
id: 'GRGzbXR',
height: 300,
theme: 'dark',
tab: 'html,result'
} %}
The href attribute provides the hyperlink that activating the link directs the user to. When a URL includes a hash mark (
#)
followed by a string of characters, that string is a fragment identifier. If that string matches an 
id of an element in the
web page, the fragment is an anchor, or bookmark, to that element. The browser will scroll to the point where the anchor is defined.
These four links point to four sections of our page identified by their 
id attribute. When the user clicks on any of the
four links in the navigation bar, the element linked to by the fragment identifier, the element containing the matching id
minus the 
#, scrolls into view.
The 
<main> content of the machine learning workshop has four sections with ids. When the site visitor clicks on one of the
links in the 
<nav>, the section with that fragment identifier scrolls into view. The markup is similar to:
<section id="reg">
  <h2>Machine Learning Workshop Tickets</h2>
</section>
<section id="about">
  <h2>What you'll learn</h2>
</section>
<section id="teachers">
  <h2>Your Instructors</h2>
  <h3>Hal 9000 <span>&amp;</span> EVE</h3>
</section>
<section id="feedback">
  <h2>What it's like to learn good and do other stuff good too</h2>
</section>
Comparing the fragment identifiers in the 
<nav> links, you'll note that each matches the 
id of a 
<section> in 
<main>.
The browser gives us a free "top of page" link. Setting 
href="#top", case-insensitive, or simply 
href="#", will scroll
the user to the top of the page.
The hash-mark separator in the 
href is not part of the fragment identifier. The fragment identifier is always the last
part of the URL and is not sent to the server.
CSS selectors
In CSS, you can target each section using an id selector, such as 
#feedback or, for less specificity, a case-sensitive
attribute selector, 
[id="feedback"].
Scripting
On MLW.com, there is an easter egg for mouse users only. Clicking the light switch toggles the page on and off.
The markup for the light switch image is:
<img src="svg/switch2.svg" id="switch"
  alt="light switch" class="light" />
The 
id attribute can be used as the parameter for the 
getElementById() method and, with a 
# prefix, as part of a
parameter for the 
querySelector() and 
querySelectorAll() methods.
const switchViaID = document.getElementById("switch");
const switchViaSelector = document.querySelector("#switch");
Our one JavaScript function makes use of this ability to target elements by their 
id attribute:
<script>
  /* switch is a reserved word in js, so we us onoff instead */
  const onoff = document.getElementById('switch');
  onoff.addEventListener('click', function(){
    document.body.classList.toggle('black');
  });
</script>
<label>
The HTML 
<label> element has a 
for attribute that takes as its value the 
id of the form control with which it is associated.
Creating an explicit label by including an 
id on every form control and pairing each with the label's 
for attribute ensures
that every form control has an associated label.
{% Codepen {
user: 'web-dot-dev',
id: 'JjZxQOB',
height: 300,
theme: 'dark',
tab: 'html,result'
} %}
While each label can be associated with exactly one form control, a form control may have more than one associated label.
{% Codepen {
user: 'web-dot-dev',
id: 'dyKaBda',
height: 300,
theme: 'dark',
tab: 'html,result'
} %}
If the form control is nested between the 
<label> opening and closing tags, the 
for and 
id attributes
aren't required: this is called an "implicit" label. Labels let all users know what each form control is for.
<label>
  Send me a reminder <input type="number" name="min"> before the workshop resumes
</label>.
The association between 
for and 
id makes the information available to users of assistive technologies. In addition,
clicking anywhere on a label gives focus to the associated element, extending the control's click area. This isn't just helpful
to people with dexterity issues making mousing less accurate; it also helps every mobile device user with fingers wider than a radio
button.
{% Codepen {
user: 'web-dot-dev',
id: 'BaVMgxo',
height: 300,
theme: 'dark',
tab: 'html,result'
} %}
In this code example, the fake fifth question of a fake quiz is a single select multiple-choice question. Each form control has an explicit
label, with a unique 
id for each. To ensure we don't accidentally duplicate an id, the id value is a combination of the question number and the value.
When including radio buttons, as the labels describe the value of the radio buttons, we encompass all the same-named buttons in a 
<fieldset>
with the 
<legend> being the label, or question, for the entire set.
Other accessibility uses
The use of 
id in accessibility and usability is not limited to labels. In introduction to text, a 
<section>
was converted into region landmark by referencing the 
id of an 
<h2> as the value of the 
<section>'s 
aria-labelledby to provide
the accessible name:
<section id="about" aria-labelledby="about_heading">
<h2 id="about_heading">What you'll learn</h2>
There are over 50 
aria-* states and properties that can be used to ensure accessibility. 
aria-labelledby, 
aria-describedby,
aria-details, and 
aria-owns take as their value a space-separated 
id reference list. 
aria-activedescendant, which
identifies the currently focused descendant element, takes as its value a single 
id reference: that of the single element
that has focus (only one element can be focused at a time).
{% Aside %}
Using 
aria-labelledby, you can create a reverse association from a form control to multiple labels, including text not
nested in a 
<label>, whether the text labels more than one form control or not. If a control has both 
<label> and 
aria-labelledby, the 
aria-labelledby
has precedence; users will not hear the 
<label> text unless the 
aria-labelledby includes the id of the label.
{% endAside %}
class
The 
class attribute provides an additional way of targeting elements with CSS (and JavaScript), but serves no other purpose
in HTML (though frameworks and component libraries may use them). The class attribute takes as its value a space-separated list
of the case-sensitive classes for the element.
{% Aside %}
Elements can be selected with CSS selectors and DOM methods based on their element names, attributes, attribute values,
position within the DOM tree, etc. Semantic HTML provides meaningful hooks, making the addition of class names often unnecessary.
The unique difference between including a class name and using 
document.getElementsByClassName() versus targeting elements
based on attributes and page structure with the more robust document.querySelectorAll() is that the former returns a live node list, the latter
is static.
{% endAside %}
Building a sound semantic structure enables the targeting of elements based on their placement and function. Sound structure
enables the use of descendant element selectors, relational selectors, and attribute selectors. As you learn about attributes
throughout this section, consider how elements with the same attributes or attribute values can be styled. It's not that you
shouldn't use the class attribute, it's just that most developers don't realize they often don't need to.
Thus far, MLW has not used any classes. Can a site be launched without a single class name? We'll see.
style
The 
style attribute enables applying inline styles, which are styles applied to the single element on which the attribute is set.
The 
style attribute takes as its value CSS property value pairs, with the value's syntax being the same as the contents of a
CSS style block: properties are followed by a colon, just like in CSS, and semicolons end each declaration, coming after the value.
The styles are only applied to the element on which the attribute is set, with descendants inheriting inherited property values if not
overridden by other style declarations on nested elements or in 
<style> blocks or style sheets. As the value comprises the equivalent of the contents
of a single style block applied to that element only, it can't be used for generated content, to create keyframe animations, or to apply any
other at-rules.
While 
style is indeed a global attribute, using it is not recommended. Rather, define styles in a separate file or files.
That said, the 
style attribute can come in handy during development to enable quick styling such as for testing purposes. Then take the
'solution' style and stick it in your linked CSS file.
tabindex
The 
tabindex attribute can be added to any element to enable it to receive focus. The 
tabindex value defines whether it
gets added to the tab order, and, optionally, into a non-default tabbing order.
The 
tabindex attribute takes as its value an integer. A negative value (the convention is to use 
-1) makes an element capable
of receiving focus, such as via JavaScript, but does not add the element to the tabbing sequence. A 
tabindex value of 
0 makes
the element focusable and reachable via tabbing, adding it to the default tab order of the page in source code order. A value of 
1
or more puts the element into a prioritized focus sequence and is not recommended.
On this page, there is a share functionality using a 
<share-action> custom element acting as a 
<button>. The 
tabindex of zero
is included to add the custom element into the keyboard default tabbing order:
<share-action authors="@estellevw" data-action="click" data-category="web.dev" data-icon="share" data-label="share, twitter" role="button" tabindex="0">
  <svg aria-label="share" role="img" xmlns="http://www.w3.org/2000/svg">
    <use href="#shareIcon" />
  </svg>
  <span>Share</span>
</share-action>
The 
role of 
button informs screen reader users that this element should behave like a button. JavaScript is used to ensure
the button functionality promise is kept; including handling both click and keydown events as well as handling Enter and Space key keypresses.
Form controls, links, buttons, and content editable elements are able to receive focus; when a keyboard user hits the tab key,
focus moves to the next focusable element as if they had 
tabindex="0" set. Other elements are not focusable by default. Adding the 
tabindex
attribute to those elements enables them to receive focus when they would otherwise not.
If a document includes elements with a 
tabindex of 
1 or more, they are included in a separate tab sequence. As you'll notice in the codepen,
tabbing begins in a separate sequence, in order of lowest value to highest value, before going through those in the regular sequence in source order.
{% Codepen {
user: 'web-dot-dev',
id: 'ExRGBPE',
height: 300,
theme: dark,
tab: 'html,result'
} %}
Altering the tabbing order can create a really bad user experience. It makes it difficult to rely on assistive technology—keyboards and screen readers alike—to navigate
your content. It is also difficult as a developer to manage and maintain. Focus is important; there is an entire module discussing focus and focus order.
role
The 
role attribute is part of the ARIA specification,
rather than the WHATWG HMTL specification. The 
role attribute can
be used to provide semantic meaning to content, enabling screen readers to inform site users of an object's expected user interaction.
There are a few common UI widgets, such as comboboxes,
menubars, tablists,
and treegrids, that have no native HTML equivalent.
For example, when creating a tabbed design pattern, the 
tab, 
tablist and
tabpanel roles can be used. Someone who can physically see
the user-interface has learned by experience how to navigate the widget and make different panels visible by clicking on associated tabs.
Including the 
tab role with 
<button role="tab"> when a group of buttons is used to show different panels lets the screen reader user know
that the 
<button> that currently has focus can toggle a related panel into view rather than implementing typical button-like functionality.
The 
role attribute doesn't change browser behavior or alter keyboard or pointer device interactions—adding 
role="button"to a 
<span>
does not turn it into a 
<button>. This is why using semantic HTML elements for their intended purpose is recommended. However, when using
the right element is not possible, the 
role attribute enables informing screen reader users when a non-semantic element has been retrofitted
into a semantic element's role.
contenteditable
An element with the 
contenteditable attribute set to 
true is editable, is focusable, and is added to the tab order as if
tabindex="0" were set. 
Contenteditable is an enumerated attribute supporting the values 
true and 
false, with a default value of 
inherit
if the attribute is not present or has an invalid value.
These three opening tags are equivalent:
<style contenteditable>
<style contenteditable="">
<style contenteditable="true">
If you include 
<style contenteditable="false">, the element is not editable (unless it's by default editable, like a 
<textarea>).
If the value is invalid, such as 
<style contenteditable="😀"> or 
<style contenteditable="contenteditable">, the value defaults to 
inherit.
To toggle between states, query the value of the HTMLElement.isContentEditable readonly property.
const editor = document.getElementById("myElement");
if(editor.contentEditable) {
  editor.setAttribute("contenteditable", "false");
} else {
  editor.setAttribute("contenteditable", "");
}
Alternatively, this property can be specified by setting 
editor.contentEditable to 
true, 
false, or 
inherit.
Global attributes can be applied to all elements, even 
<style> elements. You can use attributes and a bit of CSS to make a live CSS editor.
<style contenteditable>
style {
  color: inherit;
  display:block;
  border: 1px solid;
  font: inherit;
  font-family: monospace;
  padding:1em;
  border-radius: 1em;
  white-space: pre;
}
</style>
Try changing the 
color of the 
style to something other than 
inherit. Then try changing the 
style to a 
p selector.
Don't remove the display property or the style block will disappear.
Custom attributes
We've only touched the surface of HTML global attributes. There are even more attributes that apply to only one or a limited set of elements.
Even with hundreds of defined attributes, you may have a need for an attribute that isn't in the specification. HTML has you covered.
You can create any custom attribute you want by adding the 
data- prefix. You can name your attribute anything that starts with 
data-
followed by any lowercase series of characters that don't start with 
xml and don't contain a colon (
:).
While HTML is forgiving and won't break if you create unsupported attributes that don't start with 
data, or even if you start
your custom attribute with 
xml or include a 
:, there are benefits to creating valid custom attributes that begin with 
data-.
With custom data attributes you know that you aren't accidentally using an existing attribute name. Custom data attributes are future-proof.
While browsers won't implement default behaviors for any specific 
data- prefixed attribute, there is a built-in dataset API
to iterate through your custom attributes. Custom properties are an excellent way of communicating application-specific information
via JavaScript. Add custom attributes to elements in the form of 
data-name and access these through the DOM using 
dataset[name]
on the element in question.
<blockquote data-machine-learning="workshop"
  data-first-name="Blendan" data-last-name="Smooth"
  data-formerly="Margarita Maker" data-aspiring="Load Balancer"
  data-year-graduated="2022">
  HAL and EVE could teach a fan to blow hot air.
</blockquote>
You can use 
getAttribute() using the full attribute name, or you can take advantage of the simpler 
dataset property.
el.dataset[machineLearning]; // workshop
e.dataset.machineLearning; // workshop
The 
dataset property returns a 
DOMStringMap object of each element's 
data- attributes. There are several custom attributes
on the 
<blockquote>. The dataset property means you don't need to know what those custom attributes are in order to access their
names and values:
for (let key in el.dataset) {
  customObject[key] = el.dataset[key];
}
The attributes in this article are global, meaning they can be applied to any HTML element (though they don't all have an impact on
those elements). Up next, we take a look at the two attributes from the intro image that we didn't address—
target and 
href—and
several other element-specific attributes as we take a deeper look into links.
{% Assessment 'attributes' %}