Merge pull request #18852 from mozilla/FXA-5787

fix(settings): make elements use proper focus colors
This commit is contained in:
Mingyuan Zhao 2025-05-14 19:43:56 -04:00 committed by GitHub
commit ffcf3b8335
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 64 additions and 50 deletions

View File

@ -17,6 +17,7 @@ export const Footer = () => {
<LinkExternal
href="https://www.mozilla.org/about/?utm_source=firefox-accounts&utm_medium=Referral"
data-testid="link-mozilla"
className="focus-visible-default rounded-sm outline-offset-2"
>
<img
src={mozLogo}
@ -33,7 +34,7 @@ export const Footer = () => {
<LinkExternal
data-testid="link-privacy"
href="https://www.mozilla.org/privacy/websites/"
className="transition-standard text-xs hover:text-grey-500 hover:underline mobileLandscape:self-end"
className="transition-standard text-xs mobileLandscape:self-end hover:text-grey-500 hover:underline focus-visible-default rounded-sm"
>
Website Privacy Notice
</LinkExternal>
@ -44,7 +45,7 @@ export const Footer = () => {
<LinkExternal
data-testid="link-terms"
href="https://www.mozilla.org/about/legal/terms/services/"
className="transition-standard text-xs mobileLandscape:self-end hover:text-grey-500 hover:underline"
className="transition-standard text-xs mobileLandscape:self-end hover:text-grey-500 hover:underline focus-visible-default rounded-sm"
>
Terms of Service
</LinkExternal>

View File

@ -15,12 +15,7 @@ export const LogoLockup = ({ children, className = '' }: LogoLockupProps) => {
return (
<>
<Localized id="app-logo-alt-3">
<img
src={logo}
data-testid="logo"
className="ltr:mr-4 rtl:ml-4"
alt="Mozilla m logo"
/>
<img src={logo} data-testid="logo" alt="Mozilla m logo" />
</Localized>
<h1
data-testid="logo-text"

View File

@ -0,0 +1,14 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* This class is a baseline styling for the "focus" interactive state shared
* across components, with shape-specific styles (e.g., border-radius,
* outline-offset, etc) applied elsewhere.
* Design document for reference: https://www.figma.com/design/2ruSnPauajQGprFy6K333u
* NOTE: Using focus-visible instead of focus here because focus-visible is only
* triggered when navigating with keyboard, while focus is also triggered by
* mouse press, which is not the desired behavior for button-like components. */
.focus-visible-default:focus-visible {
@apply outline outline-blue-500 outline-2;
}

View File

@ -13,3 +13,4 @@
@import './flows.css';
@import './tooltips.css';
@import './inputs.css';
@import './focus.css';

View File

@ -104,7 +104,7 @@ export const Banner = ({
<button
aria-label={`Close banner`}
className={classNames(
'shrink-0 self-start hover:backdrop-saturate-150 focus:backdrop-saturate-200',
'shrink-0 self-start hover:backdrop-saturate-150 focus:backdrop-saturate-200 focus-visible-default rounded',
type === 'error' && 'hover:bg-red-200 focus:bg-red-300',
type === 'info' &&
!isFancy &&

View File

@ -154,7 +154,7 @@ export const BrandMessaging = ({
attrs={{ ariaLabel: true }}
>
<button
className="w-4 h-4"
className="w-4 h-4 rounded-sm focus-visible-default outline-offset-2"
data-testid="close-brand-messaging"
type="button"
aria-label="Close banner"

View File

@ -34,7 +34,7 @@ const ButtonBack = ({
data-testid={dataTestId}
title={localizedButtonTitle}
aria-label={localizedButtonAriaLabel}
className="me-4 tablet:me-0 tablet:p-4 tablet:absolute tablet:-start-24"
className="me-4 tablet:me-0 tablet:p-4 tablet:absolute tablet:-start-24 rounded focus-visible-default"
>
<BackArrow className="w-6 h-auto text-grey-400 rtl:transform rtl:-scale-x-100" />
</button>

View File

@ -93,7 +93,7 @@ export const InputPassword = ({
<button
type="button"
data-testid={formatDataTestId('visibility-toggle')}
className="absolute end-0 inset-y-0 my-auto mx-2 px-2 text-grey-500 box-content"
className="absolute end-0 inset-y-0 my-auto mx-2 px-2 text-grey-500 box-content focus-visible-default rounded"
onClick={changeVisibilityStatus}
title={
visible

View File

@ -37,8 +37,8 @@ const ResetPasswordWarning = ({
setExpanded((e.currentTarget as HTMLDetailsElement).open)
}
>
{/* Arbitrary varaite [&::-webkit-details-marker]:hidden removes the list arrow on webkit based browsers */}
<summary className="flex items-center cursor-pointer list-none [&::-webkit-details-marker]:hidden">
{/* Arbitrary variant [&::-webkit-details-marker]:hidden removes the list arrow on webkit based browsers */}
<summary className="flex items-center cursor-pointer list-none [&::-webkit-details-marker]:hidden rounded-sm focus-visible-default outline-offset-2">
<WarnIcon
role="img"
className="me-4"

View File

@ -110,7 +110,7 @@ export const AlertBar = () => {
</p>
<button
className={classNames(
'shrink-0 items-stretch justify-center py-2 px-3',
'shrink-0 items-stretch justify-center py-2 px-3 focus-visible:rounded-sm focus-visible-default',
{
'hover:bg-red-200 focus:bg-red-300': alertType() === 'error',
'hover:bg-blue-100 focus:bg-blue-200': alertType() === 'info',

View File

@ -113,7 +113,7 @@ export const BentoMenu = () => {
aria-label={bentoMenuTitle}
aria-expanded={!!isRevealed}
aria-haspopup="menu"
className="rounded p-2 mx-2 border-transparent hover:bg-grey-100 transition-standard desktop:mx-8"
className="rounded p-2 mx-2 border-transparent hover:bg-grey-100 transition-standard desktop:mx-8 focus-visible-default"
>
<BentoIcon className="w-5 text-violet-900" />
</button>
@ -128,12 +128,15 @@ export const BentoMenu = () => {
>
<div className="flex flex-wrap">
<div className="flex w-full py-4 gap-2 items-center flex-col tablet:w-auto tablet:relative">
<button onClick={closeFn} title="Close">
<CloseIcon
width="16"
height="16"
className="absolute top-5 end-5 mobileLandscape:hidden fill-current"
/>
<button
onClick={closeFn}
title="Close"
/* Clicking the bento icon again closes the menu, so
there is no need to display the close button for non-mobile
devices, even for screen readers. */
className="absolute top-5 end-5 mobileLandscape:hidden rounded-sm focus-visible-default outline-offset-2"
>
<CloseIcon width="16" height="16" className="fill-current" />
</button>
<div className="mt-12 px-8 text-center mobileLandscape:mt-0">
<FtlMsg id="bento-menu-tagline">
@ -146,7 +149,7 @@ export const BentoMenu = () => {
<LinkExternal
data-testid="desktop-link"
href={desktopLink}
className="block p-2 ps-6 hover:bg-grey-100"
className="block p-2 ps-6 hover:bg-grey-100 focus-visible:rounded-sm focus-visible-default"
onClick={() =>
GleanMetrics.accountPref.bentoFirefoxDesktop()
}
@ -163,7 +166,7 @@ export const BentoMenu = () => {
<LinkExternal
data-testid="mobile-link"
href={mobileLink}
className="block p-2 ps-6 hover:bg-grey-100"
className="block p-2 ps-6 hover:bg-grey-100 focus-visible:rounded-sm focus-visible-default"
onClick={() =>
GleanMetrics.accountPref.bentoFirefoxMobile()
}
@ -180,7 +183,7 @@ export const BentoMenu = () => {
<LinkExternal
data-testid="monitor-link"
href={monitorLink}
className="block p-2 ps-6 hover:bg-grey-100"
className="block p-2 ps-6 hover:bg-grey-100 focus-visible:rounded-sm focus-visible-default"
onClick={() => GleanMetrics.accountPref.bentoMonitor()}
>
<div className={iconClassNames}>
@ -193,7 +196,7 @@ export const BentoMenu = () => {
<LinkExternal
data-testid="relay-link"
href={relayLink}
className="block p-2 ps-6 hover:bg-grey-100"
className="block p-2 ps-6 hover:bg-grey-100 focus-visible:rounded-sm focus-visible-default"
onClick={() => GleanMetrics.accountPref.bentoRelay()}
>
<div className={iconClassNames}>
@ -208,7 +211,7 @@ export const BentoMenu = () => {
<LinkExternal
data-testid="vpn-link"
href={vpnLink}
className="block p-2 ps-6 hover:bg-grey-100"
className="block p-2 ps-6 hover:bg-grey-100 focus-visible:rounded-sm focus-visible-default"
onClick={() => GleanMetrics.accountPref.bentoVpn()}
>
<div className={iconClassNames}>
@ -221,7 +224,7 @@ export const BentoMenu = () => {
<LinkExternal
data-testid="pocket-link"
href="https://app.adjust.com/hr2n0yz?redirect_macos=https%3A%2F%2Fgetpocket.com%2Fpocket-and-firefox&redirect_windows=https%3A%2F%2Fgetpocket.com%2Fpocket-and-firefox&engagement_type=fallback_click&fallback=https%3A%2F%2Fgetpocket.com%2Ffirefox_learnmore%3Fsrc%3Dff_bento&fallback_lp=https%3A%2F%2Fapps.apple.com%2Fapp%2Fpocket-save-read-grow%2Fid309601447"
className="block p-2 ps-6 hover:bg-grey-100"
className="block p-2 ps-6 hover:bg-grey-100 focus-visible:rounded-sm focus-visible-default"
onClick={() => GleanMetrics.accountPref.bentoPocket()}
>
<div className={iconClassNames}>

View File

@ -37,7 +37,7 @@ export function ConnectAnotherDevicePromo() {
</div>
<div className="flex flex-2 justify-center mt-5 mobileLandscape:mt-0 mobileLandscape:justify-end mobileLandscape:rtl:justify-start">
<LinkExternal
className="self-center"
className="self-center rounded focus-visible-default outline-offset-2"
data-testid="play-store-link"
href="https://app.adjust.com/2uo1qc?redirect=https%3A%2F%2Fplay.google.com%2Fstore%2Fapps%2Fdetails%3Fid%3Dorg.mozilla.firefox"
onClick={() => GleanMetrics.accountPref.googlePlaySubmit()}
@ -53,7 +53,7 @@ export function ConnectAnotherDevicePromo() {
</Localized>
</LinkExternal>
<LinkExternal
className="self-center p-2"
className="self-center m-2 rounded focus-visible-default outline-offset-2"
data-testid="app-store-link"
href="https://app.adjust.com/2uo1qc?redirect=https%3A%2F%2Fitunes.apple.com%2Fus%2Fapp%2Ffirefox-private-safe-browser%2Fid989804926"
onClick={() => GleanMetrics.accountPref.appleSubmit()}

View File

@ -64,7 +64,7 @@ export const DropDownAvatarMenu = () => {
aria-label={dropDownMenuTitle}
aria-expanded={!!isRevealed}
aria-haspopup="menu"
className="rounded-full border border-transparent hover:border-purple-500 focus:border-purple-500 focus:outline-none active:border-purple-700 transition-standard"
className="rounded-full border border-transparent hover:border-purple-500 active:border-purple-700 transition-standard focus-visible-default focus-visible:border-transparent"
>
<Avatar className="w-10 rounded-full" {...{ avatar }} />
</button>
@ -96,7 +96,7 @@ export const DropDownAvatarMenu = () => {
<div className="bg-gradient-to-r from-blue-500 via-pink-700 to-yellow-500 h-px" />
<div className="px-4 py-5">
<button
className="pl-3 group"
className="ml-3 group rounded-sm focus-visible-default outline-offset-2"
onClick={signOut}
data-testid="avatar-menu-sign-out"
>

View File

@ -30,7 +30,7 @@ export const HeaderLockup = () => {
const left = (
<>
<button
className="desktop:hidden me-6 p-2 self-center -m-2 z-[1] rounded hover:bg-grey-100"
className="desktop:hidden me-6 p-2 self-center -m-2 z-[1] rounded hover:bg-grey-100 focus-visible-default"
data-testid="header-menu"
aria-label={localizedMenuText}
title={localizedMenuText}
@ -50,15 +50,15 @@ export const HeaderLockup = () => {
<a
href="#"
title="Back to top"
className="flex"
// use gap instead of margin to make the focus outline look right
// when the header title is invisible
className="flex gap-4 rounded-sm focus-visible:outline focus-visible:outline-blue-500 focus:outline-2 outline-offset-4"
data-testid="back-to-top"
>
<LogoLockup>
<>
<Localized id="header-title-2">
<span className="font-bold ltr:mr-2 rtl:ml-2">
Mozilla account
</span>
<span className="font-bold">Mozilla account</span>
</Localized>
</>
</LogoLockup>
@ -71,7 +71,7 @@ export const HeaderLockup = () => {
<LinkExternal
href="https://support.mozilla.org/products/mozilla-account"
title={localizedHelpText}
className="inline-block relative p-2 -m-2 z-[1] rounded hover:bg-grey-100"
className="inline-block relative p-2 -m-2 z-[1] rounded hover:bg-grey-100 focus-visible-default"
onClick={handleHelpLinkClick}
>
<Help

View File

@ -82,6 +82,7 @@ export const Modal = ({
data-testid="modal-dismiss"
onClick={(event) => onDismiss()}
title={ftlMsgResolver.getMsg('modal-close-title', 'Close')}
className="rounded focus-visible-default"
>
<CloseIcon className="w-4 h-4 m-3 fill-current" />
</button>

View File

@ -18,6 +18,8 @@ export interface NavRefProps {
}
const navActiveClass = 'nav-active';
const navItemClasses =
'inline-block py-1 px-2 hover:bg-grey-100 rounded-sm focus-visible-default';
// Update the active nav class when this percentage of a section is shown on screen
const STANDARD_SECTION_THRESHOLD = 0.8;
@ -151,10 +153,7 @@ export const Nav = ({
data-testid="nav-link-profile"
href="#profile"
ref={profileLinkRef}
className={classNames(
navActiveClass,
'inline-block py-1 px-2 hover:bg-grey-100'
)}
className={classNames(navActiveClass, navItemClasses)}
>
Profile
</a>
@ -165,7 +164,7 @@ export const Nav = ({
<a
href="#security"
data-testid="nav-link-security"
className="inline-block py-1 px-2 hover:bg-grey-100"
className={navItemClasses}
ref={securityLinkRef}
>
Security
@ -177,7 +176,7 @@ export const Nav = ({
<a
href="#connected-services"
data-testid="nav-link-connected-services"
className="inline-block py-1 px-2 hover:bg-grey-100"
className={navItemClasses}
ref={connectedServicesLinkRef}
>
Connected Services
@ -190,7 +189,7 @@ export const Nav = ({
<a
href="#linked-accounts"
data-testid="nav-link-linked-accounts"
className="inline-block py-1 px-2 hover:bg-grey-100"
className={navItemClasses}
ref={linkedAccountsLinkRef}
>
Linked Accounts
@ -203,7 +202,7 @@ export const Nav = ({
<a
href="#data-collection"
data-testid="nav-link-data-collection"
className="inline-block py-1 px-2 hover:bg-grey-100"
className={navItemClasses}
ref={dataCollectionLinkRef}
>
Data Collection and Use
@ -216,7 +215,7 @@ export const Nav = ({
{hasSubscription && (
<li className="mb-5">
<LinkExternal
className="font-bold"
className="font-bold focus-visible-default rounded-sm outline-offset-2"
data-testid="nav-link-subscriptions"
href="/subscriptions"
>
@ -232,7 +231,7 @@ export const Nav = ({
{marketingCommPrefLink && (
<li>
<LinkExternal
className="font-bold"
className="font-bold focus-visible-default rounded-sm outline-offset-2"
data-testid="nav-link-newsletters"
href={marketingCommPrefLink}
>

View File

@ -198,7 +198,7 @@ const ThirdPartySignInForm = ({
<button
type="submit"
className="w-full px-2 mt-2 justify-center text-black bg-transparent border-grey-300 border hover:border-black rounded-lg text-md text-center inline-flex items-center"
className="w-full px-2 mt-2 justify-center text-black bg-transparent border-grey-300 border hover:border-black rounded-lg text-md text-center inline-flex items-center focus-visible-default outline-offset-2"
onClick={onClick}
>
{buttonText}

View File

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
.switch {
@apply relative min-w-16 align-top border bg-transparent rounded-full overflow-hidden;
@apply relative min-w-16 align-top border bg-transparent rounded-full overflow-hidden focus-visible-default;
height: calc(1.5rem + 2px); /* 2px increase accounts for the border */
.slider {