From 1e9c94b7886ae3adde7ae0976705d75091dba7d7 Mon Sep 17 00:00:00 2001
From: yyh <92089059+lyzno1@users.noreply.github.com>
Date: Mon, 25 May 2026 10:22:34 +0800
Subject: [PATCH] fix(web): clean up header logo accessibility (#36567)
---
web/app/account/(commonLayout)/header.tsx | 14 ++++++---
.../base/logo/__tests__/dify-logo.spec.tsx | 6 ++++
web/app/components/base/logo/dify-logo.tsx | 4 ++-
.../header/__tests__/index.spec.tsx | 22 +++++++-------
web/app/components/header/index.tsx | 30 ++++++++++---------
5 files changed, 47 insertions(+), 29 deletions(-)
diff --git a/web/app/account/(commonLayout)/header.tsx b/web/app/account/(commonLayout)/header.tsx
index 13d9779e9c..8507ce1a2c 100644
--- a/web/app/account/(commonLayout)/header.tsx
+++ b/web/app/account/(commonLayout)/header.tsx
@@ -5,6 +5,7 @@ import { useSuspenseQuery } from '@tanstack/react-query'
import { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import DifyLogo from '@/app/components/base/logo/dify-logo'
+import Link from '@/next/link'
import { useRouter } from '@/next/navigation'
import { systemFeaturesQueryOptions } from '@/service/system-features'
import Avatar from './avatar'
@@ -17,21 +18,26 @@ const Header = () => {
const goToStudio = useCallback(() => {
router.push('/apps')
}, [router])
+ const logoLabel = systemFeatures.branding.enabled && systemFeatures.branding.application_title ? systemFeatures.branding.application_title : 'Dify'
return (
-
+
{systemFeatures.branding.enabled && systemFeatures.branding.login_page_logo
? (

)
- :
}
-
+ :
}
+
{t('account.account', { ns: 'common' })}
diff --git a/web/app/components/base/logo/__tests__/dify-logo.spec.tsx b/web/app/components/base/logo/__tests__/dify-logo.spec.tsx
index f465c47e03..b3b258c9a1 100644
--- a/web/app/components/base/logo/__tests__/dify-logo.spec.tsx
+++ b/web/app/components/base/logo/__tests__/dify-logo.spec.tsx
@@ -58,6 +58,12 @@ describe('DifyLogo', () => {
const img = screen.getByRole('img', { name: /dify logo/i })
expect(img).toHaveClass('custom-test-class')
})
+
+ it('applies custom alt text', () => {
+ const { container } = render(
)
+ const img = container.querySelector('img')
+ expect(img).toHaveAttribute('alt', '')
+ })
})
describe('Theme behavior', () => {
diff --git a/web/app/components/base/logo/dify-logo.tsx b/web/app/components/base/logo/dify-logo.tsx
index 0250e8c913..f748044fc6 100644
--- a/web/app/components/base/logo/dify-logo.tsx
+++ b/web/app/components/base/logo/dify-logo.tsx
@@ -23,12 +23,14 @@ type DifyLogoProps = {
style?: LogoStyle
size?: LogoSize
className?: string
+ alt?: string
}
const DifyLogo: FC
= ({
style = 'default',
size = 'medium',
className,
+ alt = 'Dify logo',
}) => {
const { theme } = useTheme()
const themedStyle = (theme === 'dark' && style === 'default') ? 'monochromeWhite' : style
@@ -37,7 +39,7 @@ const DifyLogo: FC = ({
)
}
diff --git a/web/app/components/header/__tests__/index.spec.tsx b/web/app/components/header/__tests__/index.spec.tsx
index 0e9ef6493d..a5e388efe3 100644
--- a/web/app/components/header/__tests__/index.spec.tsx
+++ b/web/app/components/header/__tests__/index.spec.tsx
@@ -1,4 +1,4 @@
-import type { ReactElement } from 'react'
+import type { AnchorHTMLAttributes, ReactElement } from 'react'
import { fireEvent, screen } from '@testing-library/react'
import { vi } from 'vitest'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
@@ -55,7 +55,7 @@ vi.mock('@/context/workspace-context-provider', () => ({
}))
vi.mock('@/next/link', () => ({
- default: ({ children, href }: { children?: React.ReactNode, href?: string }) => {children},
+ default: ({ children, href, ...props }: AnchorHTMLAttributes & { href?: string }) => {children},
}))
let mockIsWorkspaceEditor = false
@@ -122,7 +122,9 @@ describe('Header', () => {
it('should render header with main nav components', () => {
renderHeader()
- expect(screen.getByRole('img', { name: /dify logo/i })).toBeInTheDocument()
+ expect(screen.getByRole('link', { name: 'Dify' })).toHaveAttribute('href', '/apps')
+ expect(screen.queryByRole('heading', { level: 1 })).not.toBeInTheDocument()
+ expect(screen.queryByRole('img', { name: /dify logo/i })).not.toBeInTheDocument()
expect(screen.getByTestId('workplace-selector')).toBeInTheDocument()
expect(screen.getByTestId('app-nav')).toBeInTheDocument()
expect(screen.getByTestId('account-dropdown')).toBeInTheDocument()
@@ -166,7 +168,7 @@ describe('Header', () => {
mockMedia = 'mobile'
renderHeader()
- expect(screen.getByRole('img', { name: /dify logo/i })).toBeInTheDocument()
+ expect(screen.getByRole('link', { name: 'Dify' })).toHaveAttribute('href', '/apps')
expect(screen.queryByTestId('env-nav')).not.toBeInTheDocument()
})
@@ -177,8 +179,8 @@ describe('Header', () => {
renderHeader()
- expect(screen.getByText('Acme Workspace')).toBeInTheDocument()
- expect(screen.getByRole('img', { name: /logo/i })).toBeInTheDocument()
+ expect(screen.getByRole('link', { name: 'Acme Workspace' })).toHaveAttribute('href', '/apps')
+ expect(screen.queryByRole('img', { name: /logo/i })).not.toBeInTheDocument()
expect(screen.queryByRole('img', { name: /dify logo/i })).not.toBeInTheDocument()
})
@@ -189,18 +191,18 @@ describe('Header', () => {
renderHeader()
- expect(screen.getByText('Custom Title')).toBeInTheDocument()
- expect(screen.getByRole('img', { name: /dify logo/i })).toBeInTheDocument()
+ expect(screen.getByRole('link', { name: 'Custom Title' })).toHaveAttribute('href', '/apps')
+ expect(screen.queryByRole('img', { name: /dify logo/i })).not.toBeInTheDocument()
})
- it('should show default Dify text when branding enabled but no application_title', () => {
+ it('should use default Dify link label when branding enabled but no application_title', () => {
mockBrandingEnabled = true
mockBrandingTitle = null
mockBrandingLogo = null
renderHeader()
- expect(screen.getByText('Dify')).toBeInTheDocument()
+ expect(screen.getByRole('link', { name: 'Dify' })).toHaveAttribute('href', '/apps')
})
it('should show dataset nav for editor who is not dataset operator', () => {
diff --git a/web/app/components/header/index.tsx b/web/app/components/header/index.tsx
index 8e94a831d4..fc0b9f2c58 100644
--- a/web/app/components/header/index.tsx
+++ b/web/app/components/header/index.tsx
@@ -44,21 +44,23 @@ const Header = () => {
setShowAccountSettingModal({ payload: ACCOUNT_SETTING_TAB.BILLING })
}, [isFreePlan, setShowAccountSettingModal, setShowPricingModal])
+ const logoLabel = isBrandingEnabled && systemFeatures.branding.application_title ? systemFeatures.branding.application_title : 'Dify'
const renderLogo = () => (
-
-
- {isBrandingEnabled && systemFeatures.branding.application_title ? systemFeatures.branding.application_title : 'Dify'}
- {systemFeatures.branding.enabled && systemFeatures.branding.workspace_logo
- ? (
-
- )
- : }
-
-
+
+ {systemFeatures.branding.enabled && systemFeatures.branding.workspace_logo
+ ? (
+
+ )
+ : }
+
)
if (isMobile) {