-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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
Improve icon a11y #5424
Improve icon a11y #5424
Conversation
e9d66ee
to
d576ff7
Compare
9c30078
to
ff9b50e
Compare
client/app/components/ApplicationArea/ApplicationLayout/VersionInfo.jsx
Outdated
Show resolved
Hide resolved
} | ||
if (alreadyInGroup) { | ||
return ( | ||
<Tooltip title="Already selected"> | ||
<i className="fa fa-check" /> | ||
<i className="fa fa-check" aria-hidden="true" /> | ||
<span className="sr-only">Already selected</span> |
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.
I feel like tooltips should have accessibility support by Antd rather than us adding manually to each of our uses. However it doesn't 😕, so I'm no so sure how to proceed anyway. Maybe we should have a component to make it easier to drop off once Antd starts to have accessible tooltips?
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.
Tooltips are sort of a pain I will try to handle separately. In the meantime I'm uncertain whether I should provide a minimal approach to them or wait until they can be dealt with. Probably I'll just remove these changes.
The high level bullet points definitely make a lot of sense. The aria tag looks great. Wrt the antd or our design system, I will defer to our awesome engs. :) |
@@ -15,7 +15,7 @@ export default function VersionInfo() { | |||
{/* eslint-disable react/jsx-no-target-blank */} | |||
<Link href="https://version.redash.io/" className="update-available" target="_blank" rel="noopener"> | |||
Update Available <i className="fa fa-external-link m-l-5" aria-hidden="true" /> | |||
<span className="sr-only">(External link)</span> | |||
<span className="sr-only">{"(External link)"}</span> |
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.
Sorry, I may have been not that clear since I also put the quotes, but what I mean is: does this need this at all? Can't it be just <span className="sr-only">(External link)</span>
?
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.
No, it can't. I changed back bc I thought this way was clearer.
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.
Why it can't? HTML/jsx wise there's nothing that holds you from writing it directly (we do it in several other places in the codebase). As for screen-readers I don't really see how having it escaped would make a difference 🤔
I'm just curious because this really looks weird to me
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.
For some reason it didn't work on my initial tests but now it seems fine. Thanks for pointing this, just reverted it.
client/app/components/BigMessage.jsx
Outdated
@@ -3,7 +3,7 @@ import PropTypes from "prop-types"; | |||
|
|||
function BigMessage({ message, icon, children, className }) { | |||
return ( | |||
<div className={"big-message p-15 text-center " + className}> | |||
<div className={"big-message p-15 text-center " + className} aria-live="assertive"> |
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.
Oriented by this and the notification guide.
<Button data-test="QueryPageHeaderMoreButton"> | ||
<EllipsisOutlinedIcon rotate={90} /> | ||
<Button data-test="QueryPageHeaderMoreButton" aria-label="More actions"> | ||
<EllipsisOutlinedIcon rotate={90} aria-label="" /> |
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.
May be a newbie question as I'm no expert with those, but what's aria-label=""
used for? Why not aria-hidden="true"
?
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.
The intention here is to make sure Ant's aria-label
s will not be displayed, so as to avoid confusion. Theoretically aria-hidden
does the trick, but I wanted to override it in some cases either way. Not a lot to back me up on this, though.
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.
Just checked with a real SR. It does the trick.
@@ -16,16 +15,18 @@ export default function EmailSettingsWarning({ featureName, className, mode, adm | |||
} | |||
|
|||
const message = ( | |||
<span> | |||
<span id="sr-mail-description"> |
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.
Same thing about the id here
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.
This one is actually Ok, because it's not being replicated in a way that could end up rendering two on the screen.
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.
I think, in general though, it might be best to generate ids for accessibility. It prevents us from colliding as well as relying on them in ways we shouldn't (e.g. using document.getElementById
in a different component, or in a test).
|
||
return ( | ||
<div className="parameter-apply-button" data-show={!!paramCount} data-test="ParameterApplyButton"> | ||
{/* TODO: This button stays detectable even when invisible */} |
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.
Same here, but I'd actually favor just creating Follow Up issues to track these instead of putting TODO
s in the application (they are usually forsaken).
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.
I've been doing both, particularly because I intend to tackle these in the near future and it helps me keeping it in mind. Are you in favor of not keeping the comments for a particular reason?
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.
My reason is that they bring little or no value. Even more when it is about new features as they always have a "room to be improved". The result is that we start to have multiple comments in the codebase that are not relevant to who's reading the code as they won't even be aware of the context 🤷♂️.
That said, I'm against TODO comments in the code. There are a couple of exceptions I consider for them however:
- When you actually want to index your files with some easily searchable term (e.g.: we used
ANGULAR_REMOVE_ME
to track any of the still dependent leftovers while migrating away from it) - When the
TODO
is actually relevant to anyone that will read the code (I can't think about an example for this now 😕)
Anyway, this is more of an opinion, maybe someone else has a different thought...
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.
SGTM!
client/app/components/queries/QueryEditor/AutocompleteToggle.jsx
Outdated
Show resolved
Hide resolved
client/app/components/BigMessage.jsx
Outdated
|
||
function BigMessage({ message, icon, children, className }) { | ||
const messageId = uniqueId("bm-message"); |
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.
This one has to be in a useRef
:
const messageIdRef = useRef();
if (!messageIdRef.current) {
messageIdRef.current = uniqueId("bm-message");
}
otherwise it will regenerate the id on every re-render.
Also in the other component (EmailSettingsWarning) as it is not specific to a a page (it could be used anywhere), maybe it's safer to do the same thing in there too?
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.
Maybe just:
const messageId = uniqueId("bm-message"); | |
const { current: messageId } = useRef(uniqueId("bm-message")); |
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.
This partially solves the thing as it will execute uniqueId
regardless. Problem with this is that iirc, Lodash uses some sort of global var to track and sum up the ids. (We would end up with some possibly big ones 😝)
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.
In brief, that was to follow this as that will avoid the component id to be updated, but not the Lodash reference to the "next id"
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.
Aside from the messageId ref conversation, just nits! Way to go! This is a huge step forward!
client/app/components/BigMessage.jsx
Outdated
|
||
function BigMessage({ message, icon, children, className }) { | ||
const messageId = uniqueId("bm-message"); |
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.
Maybe just:
const messageId = uniqueId("bm-message"); | |
const { current: messageId } = useRef(uniqueId("bm-message")); |
client/app/components/BigMessage.jsx
Outdated
aria-live="assertive" | ||
aria-relevant="additions removals"> | ||
<h3 className="m-t-0 m-b-0" aria-labelledby={messageId}> | ||
<i className={"fa " + icon} aria-hidden="true" /> |
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.
Do or not: could use classnames
, not a big deal.
@@ -16,16 +15,18 @@ export default function EmailSettingsWarning({ featureName, className, mode, adm | |||
} | |||
|
|||
const message = ( | |||
<span> | |||
<span id="sr-mail-description"> |
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.
I think, in general though, it might be best to generate ids for accessibility. It prevents us from colliding as well as relying on them in ways we shouldn't (e.g. using document.getElementById
in a different component, or in a test).
<> | ||
{" "} | ||
<i className="fa fa-external-link" style={{ marginLeft: 5 }} aria-hidden="true" /> | ||
<span className="sr-only">(opens in a new tab)</span> |
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.
Feels like this is getting repeated, some. I don't have a great idea for abstracting it, yet, but it feels like it maybe could be.
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.
Coming soon 😉
<i className={cx("zmdi zmdi-refresh", { "zmdi-hc-spin": refreshClickButtonId === 1 })} />{" "} | ||
<i className={cx("zmdi zmdi-refresh", { "zmdi-hc-spin": refreshClickButtonId === 1 })} aria-hidden="true" /> | ||
<span className="sr-only"> | ||
{refreshClickButtonId === 1 ? "Refreshing, please wait. " : "Press to refresh. "} |
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.
Do or not: feels like some duplication, here -- if you feel like you can abstract it, go for it! But if you think it could create business logic changes, don't worry about it.
@@ -94,7 +94,8 @@ function NotificationTemplate({ alert, query, columnNames, resultValues, subject | |||
data-test="CustomBody" | |||
/> | |||
<HelpTrigger type="ALERT_NOTIF_TEMPLATE_GUIDE" className="f-13"> | |||
<i className="fa fa-question-circle" /> Formatting guide | |||
<i className="fa fa-question-circle" aria-hidden="true" /> Formatting guide | |||
<span className="sr-only"> (help)</span> |
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.
(nit) Extra space?
client/app/lib/hooks/useLazyRef.ts
Outdated
return lazyRef as React.MutableRefObject<T>; | ||
} | ||
|
||
export default useLazyRef; |
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.
nit: prefer the named export export function useLazyRef(...)
client/app/lib/hooks/useUniqueId.ts
Outdated
return id; | ||
} | ||
|
||
export default useUniqueId; |
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.
same thing about the named export 🙂
b96692d
to
ee8ebb3
Compare
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.
Thanks for the work and patience here @rafawendel 🐳
What type of PR is this? (check all applicable)
Description
This aims to add accessibility to icons by:
aria-hidden
aria-label
,aria-labelledby
andaria-describedby
where applicableAnt Icons already have somewhat comprehensible labels 🎉, so only particularly relevant ones will be a11y-zed
Related Tickets & Documents
#5418, #5419, #5420, #5421
Screenshots
This PR is not supposed to result in visual changes or regressions, but I used the opportunity to fix minor ones.
(Cc. @wenbow)
Note for reviewers
The commit order is intended to be comprehensive to review.