diff --git a/frontend/src/lib/components/OcrProgressBar.svelte b/frontend/src/lib/components/OcrProgressBar.svelte
new file mode 100644
index 00000000..2713b3c3
--- /dev/null
+++ b/frontend/src/lib/components/OcrProgressBar.svelte
@@ -0,0 +1,39 @@
+
+
+{#if totalPages > 0}
+
+
+
+ {currentPage} / {totalPages}
+
+ {#if skippedPages > 0}
+
+ {skippedPages} Seiten übersprungen
+
+ {/if}
+
+{/if}
diff --git a/frontend/src/lib/components/OcrProgressBar.svelte.spec.ts b/frontend/src/lib/components/OcrProgressBar.svelte.spec.ts
new file mode 100644
index 00000000..795850e1
--- /dev/null
+++ b/frontend/src/lib/components/OcrProgressBar.svelte.spec.ts
@@ -0,0 +1,43 @@
+import { describe, it, expect, afterEach } from 'vitest';
+import { cleanup, render } from 'vitest-browser-svelte';
+import { page } from 'vitest/browser';
+import OcrProgressBar from './OcrProgressBar.svelte';
+
+afterEach(cleanup);
+
+describe('OcrProgressBar', () => {
+ it('renders progress bar with correct ARIA attributes', async () => {
+ render(OcrProgressBar, { currentPage: 2, totalPages: 5 });
+ const bar = page.getByRole('progressbar');
+ await expect.element(bar).toHaveAttribute('aria-valuenow', '2');
+ await expect.element(bar).toHaveAttribute('aria-valuemax', '5');
+ });
+
+ it('hides progress bar when totalPages is zero', async () => {
+ render(OcrProgressBar, { currentPage: 0, totalPages: 0 });
+ await expect.element(page.getByRole('progressbar')).not.toBeInTheDocument();
+ });
+
+ it('fills to 100 percent when current equals total', async () => {
+ render(OcrProgressBar, { currentPage: 5, totalPages: 5 });
+ const fill = page.getByTestId('progress-fill');
+ await expect.element(fill).toBeInTheDocument();
+ const el = fill.element() as HTMLElement;
+ expect(el.style.width).toBe('100%');
+ });
+
+ it('shows page counter text', async () => {
+ render(OcrProgressBar, { currentPage: 3, totalPages: 7 });
+ await expect.element(page.getByText('3 / 7')).toBeInTheDocument();
+ });
+
+ it('shows skipped pages warning when skippedPages > 0', async () => {
+ render(OcrProgressBar, { currentPage: 5, totalPages: 5, skippedPages: 2 });
+ await expect.element(page.getByTestId('skipped-warning')).toBeInTheDocument();
+ });
+
+ it('does not show warning when skippedPages is 0', async () => {
+ render(OcrProgressBar, { currentPage: 3, totalPages: 5, skippedPages: 0 });
+ await expect.element(page.getByTestId('skipped-warning')).not.toBeInTheDocument();
+ });
+});