diff --git a/app/components/SuccessGuide.accessibility.test.tsx b/app/components/SuccessGuide.accessibility.test.tsx
new file mode 100644
index 000000000..371b757b4
--- /dev/null
+++ b/app/components/SuccessGuide.accessibility.test.tsx
@@ -0,0 +1,87 @@
+import { render, screen } from '@testing-library/react';
+import '@testing-library/jest-dom/vitest';
+import { describe, it, expect, vi } from 'vitest';
+import { SuccessGuide } from './SuccessGuide';
+
+type MockMotionProps = {
+ children?: React.ReactNode;
+ className?: string;
+ [key: string]: unknown;
+};
+
+vi.mock('framer-motion', () => ({
+ motion: {
+ div: ({ children, ...props }: MockMotionProps) =>
{children}
,
+ },
+ AnimatePresence: ({ children }: { children?: React.ReactNode }) => <>{children}>,
+}));
+
+vi.mock('./Icons', () => ({
+ CloseIcon: () => ,
+}));
+
+vi.mock('@/context/TranslationContext', () => ({
+ useTranslation: () => ({
+ t: (key: string) => key,
+ }),
+}));
+
+const defaultProps = {
+ markdown: '',
+ onDismiss: vi.fn(),
+};
+
+describe('SuccessGuide — Accessibility & Screen Reader Compliance', () => {
+ it('renders as a named region landmark linked to h2 via aria-labelledby', () => {
+ const { container } = render();
+
+ const region = container.querySelector('[role="region"]');
+ expect(region).toBeInTheDocument();
+ expect(region).toHaveAttribute('aria-labelledby', 'success-guide-heading');
+
+ const heading = screen.getByRole('heading', { level: 2 });
+ expect(heading).toHaveAttribute('id', 'success-guide-heading');
+ expect(heading).toHaveTextContent('success_guide.title');
+ });
+
+ it('renders dismiss button with aria-label and correct button role', () => {
+ render();
+
+ const dismissButton = screen.getByRole('button', { name: 'Dismiss guide' });
+ expect(dismissButton).toBeInTheDocument();
+ expect(dismissButton.tagName).toBe('BUTTON');
+ });
+
+ it('renders steps grid with aria-label and all 4 step titles visible', () => {
+ const { container } = render();
+
+ const stepsGrid = container.querySelector('[aria-label="Steps to embed your badge"]');
+ expect(stepsGrid).toBeInTheDocument();
+
+ expect(screen.getByText('success_guide.step_1_title')).toBeInTheDocument();
+ expect(screen.getByText('success_guide.step_2_title')).toBeInTheDocument();
+ expect(screen.getByText('success_guide.step_3_title')).toBeInTheDocument();
+ expect(screen.getByText('success_guide.step_4_title')).toBeInTheDocument();
+ });
+
+ it('renders step numbers as visible text for screen reader sequence announcement', () => {
+ render();
+
+ expect(screen.getByText('01')).toBeInTheDocument();
+ expect(screen.getByText('02')).toBeInTheDocument();
+ expect(screen.getByText('03')).toBeInTheDocument();
+ expect(screen.getByText('04')).toBeInTheDocument();
+ });
+
+ it('renders markdown snippet in code element with aria-label and hides $ symbol', () => {
+ const { container } = render();
+
+ const codeEl = container.querySelector('code[aria-label="Your badge markdown snippet"]');
+ expect(codeEl).toBeInTheDocument();
+ expect(codeEl).toHaveTextContent(defaultProps.markdown);
+
+ const dollar = container.querySelector('[aria-hidden="true"].select-none');
+ expect(dollar).toBeInTheDocument();
+ expect(dollar).toHaveTextContent('$');
+ });
+});
diff --git a/app/components/SuccessGuide.tsx b/app/components/SuccessGuide.tsx
index e4c46d013..4af234080 100644
--- a/app/components/SuccessGuide.tsx
+++ b/app/components/SuccessGuide.tsx
@@ -45,16 +45,21 @@ export function SuccessGuide({ markdown, onDismiss }: SuccessGuideProps) {
className="max-w-4xl mx-auto mb-12"
>
-
+
-
+
@@ -62,7 +67,10 @@ export function SuccessGuide({ markdown, onDismiss }: SuccessGuideProps) {
{t('success_guide.markdown_copied')}
-
+
{t('success_guide.title')}
@@ -77,7 +85,10 @@ export function SuccessGuide({ markdown, onDismiss }: SuccessGuideProps) {
-
+
{steps.map((step, i) => (
- $
-
+
+ $
+
+
{markdown}