-
Notifications
You must be signed in to change notification settings - Fork 776
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(standards): add html elems object #2325
Conversation
Co-authored-by: Wilco Fiers <WilcoFiers@users.noreply.github.com>
lib/standards/html-elms.js
Outdated
// Source: https://www.w3.org/TR/html-aam-1.0/#html-element-role-mappings | ||
const htmlElms = { | ||
a: { | ||
features: [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thought about this for a while... I think this is the right idea, but we can improve on this a little:
const htmlElms = {
a: {
variant: {
'hyperlink': {
matches: {
attributes: { href: '/.*/' }
},
implicitRole: 'link',
allowedRoles: [...linkRoles]
},
'no href': {
matches: {
attributes: { href: null }
},
implicitRole: null,
allowedRoles: true
}
}
}
}
This has a bunch of advantages:
- Using an array is problematic in configuration. With an array, there is no way to modify a single property inside one of the variants. You can't even update one, since our axe.configure replaces Arrays with whatever we pass in, instead of assigning props and leaving the existing stuff in tact.
- Adding keys also makes it easier to understand what these things are doing at a glance. That's good for us when we work on this, it also makes configuration files easier to understand. I'm using language from html-aam here as a callback, should make these easier to look up.
- I don't think "feature" describes what this is. It's a "type", but because that's an overloaded word, maybe "variant"?
- I thought about instead of calling this "feature" just to use "allowedRoles" and "value", but that makes this noisy when adding implicitRole in, which we'll need to do
We should probably put text.nativeElementType
into this structure in the future too.
This pr got messed up somewhere in the merging and branching. Going to open another clean one. |
Note: the object is incomplete and this pr is here to start discussing the object and structure. Since the object is so large multiple smaller prs that can be easier to verify the information is correct would be better.
The lookup table has a few different objects that try to convey HTML spec related things.
elementsAllowedAnyRole
,elementsAllowedNoRole
, andevaluateRoleForElement
.evaluateRoleForElement
is a bunch of functions that can't even be serialized. Also, there are a few commons functions that need HTML spec information such astext.nativeElementTypes
andsubtree-text.js
needing to know phrasing content type elements.The aria
roles
object has a propertyallowedElements
which is an inverse property lookup to the spec table found in https://www.w3.org/TR/html-aria/#docconformance. This means that to generate the list of allowed elements, you need to find each element the role is allowed on rather than looking at the element row and seeing which roles are allowed. This makes it extremely easy to miss things, for example:This object puts all that information into a serializable standards object that can be configured as well. It removes the need for
evaluateRoleForElement
and makes that information configurable.The object is defined as such and the information was taken from https://www.w3.org/TR/html-aria/#docconformance:
It also simplifies and enhances the check for
aria-allowed-attr
andaria-allowed-role
. For example, theis-aria-role-allowed-on-element
function has to perform 3 different matches functions looking at theelementsAllowedAnyRole
,elementsAllowedNoRole
,allowedElements
andevaluateRoleForElement
. Instead, it can just look at the HTML spec table and see which roles are allowed on the element:The table also allows us to catch elements which aren't allowed global aria elements in
aria-allowed-attr
. For example,<col aria-label="foo"></col>
should not pass ascol
is not allowed any aria attributes.Lastly, the object defines
implicitAttrs
which allow us to remove the "hacks" inariaRequiredAttrEvaluate
by defining which HTML elements define default aria attributes. This means<h1 role="heading">foo</h1>
should pass since theh1
element defaultsaria-level
to the level of the element.We'll need to talk about how to handle the content types of each element. Having them in place would greatly help for #601 as knowing which elements are interactive content types would let us know to flag them. However, they get a bit messy in their requirements of when it's interactive or not and duplicates a some of the properties when that's the only difference between them. For example,
audio
is an interactive element only when it has acontrols
attribute, but the other properties ofallowedRole
andallowedAttrs
is the same regardless.Personally, I think it should be in it's own object so we don't have to conflict with this object. For example:
img
is an interactive content model if theusemap
attribute is present, but should be part of the 3 other features of allowed roles or attrs. Doing this would require 6 different objects to ensure the combinations are intact, which is a bit much.Reviewer checks
Required fields, to be filled out by PR reviewer(s)