diff --git a/superset-frontend/src/components/Accessibility/VisuallyHidden.test.tsx b/superset-frontend/src/components/Accessibility/VisuallyHidden.test.tsx
new file mode 100644
index 000000000000..a5708e7fd1b4
--- /dev/null
+++ b/superset-frontend/src/components/Accessibility/VisuallyHidden.test.tsx
@@ -0,0 +1,54 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { render, screen } from 'spec/helpers/testing-library';
+import VisuallyHidden from './VisuallyHidden';
+
+test('renders children', () => {
+ render(Screen-reader only text);
+ expect(screen.getByText('Screen-reader only text')).toBeInTheDocument();
+});
+
+test('renders as span by default', () => {
+ render(Default tag);
+ const el = screen.getByText('Default tag');
+ expect(el.tagName).toBe('SPAN');
+});
+
+test('renders as a custom element when as prop is provided', () => {
+ render(Page heading);
+ const el = screen.getByText('Page heading');
+ expect(el.tagName).toBe('H1');
+});
+
+test('forwards id and className props', () => {
+ render(
+
+ Text
+ ,
+ );
+ const el = screen.getByText('Text');
+ expect(el).toHaveAttribute('id', 'my-id');
+ expect(el).toHaveClass('my-class');
+});
+
+test('applies clip-rect style for screen-reader-only behavior', () => {
+ render(Hidden);
+ const el = screen.getByText('Hidden');
+ expect(el).toHaveStyle({ position: 'absolute' });
+});
diff --git a/superset-frontend/src/components/Accessibility/VisuallyHidden.tsx b/superset-frontend/src/components/Accessibility/VisuallyHidden.tsx
new file mode 100644
index 000000000000..c827bb9dbce5
--- /dev/null
+++ b/superset-frontend/src/components/Accessibility/VisuallyHidden.tsx
@@ -0,0 +1,60 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { ElementType, FC, ReactNode } from 'react';
+import { styled } from '@apache-superset/core/theme';
+
+/**
+ * VisuallyHidden — content that is available to assistive technology but not
+ * visually rendered. Use for screen-reader-only headings, labels, and live
+ * regions where a duplicate visible element would be redundant.
+ *
+ * Renders a `` by default. Pass `as` to render a different element
+ * (e.g. `as="h1"` for an sr-only page heading).
+ */
+const HiddenElement = styled.span`
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ white-space: nowrap;
+ border: 0;
+`;
+
+export interface VisuallyHiddenProps {
+ /** Element type to render. Defaults to `'span'`. */
+ as?: ElementType;
+ children?: ReactNode;
+ id?: string;
+ className?: string;
+}
+
+const VisuallyHidden: FC = ({
+ as = 'span',
+ children,
+ ...rest
+}) => (
+
+ {children}
+
+);
+
+export default VisuallyHidden;
diff --git a/superset-frontend/src/components/Accessibility/index.tsx b/superset-frontend/src/components/Accessibility/index.tsx
new file mode 100644
index 000000000000..0a81b1e06f72
--- /dev/null
+++ b/superset-frontend/src/components/Accessibility/index.tsx
@@ -0,0 +1,22 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+export {
+ default as VisuallyHidden,
+ type VisuallyHiddenProps,
+} from './VisuallyHidden';
diff --git a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx
index a507c65318de..e27fd6a711f8 100644
--- a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx
+++ b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx
@@ -25,6 +25,7 @@ import { css, styled, useTheme } from '@apache-superset/core/theme';
import { useDispatch, useSelector } from 'react-redux';
import { EmptyState, Loading } from '@superset-ui/core/components';
import { ErrorBoundary, BasicErrorAlert } from 'src/components';
+import { VisuallyHidden } from 'src/components/Accessibility';
import BuilderComponentPane from 'src/dashboard/components/BuilderComponentPane';
import DashboardHeader from 'src/dashboard/components/Header';
import { Icons } from '@superset-ui/core/components/Icons';
@@ -351,6 +352,7 @@ const StyledDashboardContent = styled.div<{
`}
`;
+
const ELEMENT_ON_SCREEN_OPTIONS = {
threshold: [1],
};
@@ -509,10 +511,13 @@ const DashboardBuilder = () => {
{!hideDashboardHeader && }
{showFilterBar &&
filterBarOrientation === FilterBarOrientation.Horizontal && (
-
+ <>
+ {t('Filters')}
+
+ >
)}
>
),
@@ -581,6 +586,7 @@ const DashboardBuilder = () => {
hidden={isReport}
data-test="dashboard-filters-panel"
>
+ {t('Filters')}
{
{renderDraggableContent}
+ {t('Dashboard content')}
{!editMode &&
!topLevelTabs &&
diff --git a/superset-frontend/src/dashboard/components/Header/index.tsx b/superset-frontend/src/dashboard/components/Header/index.tsx
index 522a22f1eca6..0638c6fa37a4 100644
--- a/superset-frontend/src/dashboard/components/Header/index.tsx
+++ b/superset-frontend/src/dashboard/components/Header/index.tsx
@@ -28,6 +28,7 @@ import { t } from '@apache-superset/core/translation';
import { Global } from '@emotion/react';
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
import { bindActionCreators } from 'redux';
+import { VisuallyHidden } from 'src/components/Accessibility';
import { LOG_ACTIONS_TOGGLE_EDIT_DASHBOARD } from 'src/logger/LogUtils';
import { Icons } from '@superset-ui/core/components/Icons';
import {
@@ -827,6 +828,9 @@ const Header = (): JSX.Element => {
data-test-id={dashboardInfo.id}
className="dashboard-header-container"
>
+
+ {dashboardTitle || t('Dashboard')}
+
= ({
return (
<>
+ {sliceName || t('Explore chart')}
- {t('Create a new chart')}
+ {t('Create a new chart')}
{t('Choose a dataset')}}
diff --git a/superset-frontend/src/pages/Home/index.tsx b/superset-frontend/src/pages/Home/index.tsx
index e270fd9872c3..070611a1a0cd 100644
--- a/superset-frontend/src/pages/Home/index.tsx
+++ b/superset-frontend/src/pages/Home/index.tsx
@@ -49,6 +49,7 @@ import { Switch } from '@superset-ui/core/components/Switch';
import getBootstrapData from 'src/utils/getBootstrapData';
import { TableTab } from 'src/views/CRUD/types';
import SubMenu, { SubMenuProps } from 'src/features/home/SubMenu';
+import { VisuallyHidden } from 'src/components/Accessibility';
import { userHasPermission } from 'src/dashboard/util/permissionUtils';
import { WelcomePageLastTab } from 'src/features/home/types';
import ActivityTable from 'src/features/home/ActivityTable';
@@ -350,6 +351,7 @@ function Welcome({ user, addDangerToast }: WelcomeProps) {
)}
+ {t('Home')}
{WelcomeMessageExtension && }
{WelcomeTopExtension && }
{WelcomeMainExtension && }