diff --git a/frontend/src/lib/planner/RecipePickerDrawer.svelte b/frontend/src/lib/planner/RecipePickerDrawer.svelte
new file mode 100644
index 0000000..3719288
--- /dev/null
+++ b/frontend/src/lib/planner/RecipePickerDrawer.svelte
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+ Rezept wählen
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/lib/planner/RecipePickerDrawer.test.ts b/frontend/src/lib/planner/RecipePickerDrawer.test.ts
new file mode 100644
index 0000000..2ba8733
--- /dev/null
+++ b/frontend/src/lib/planner/RecipePickerDrawer.test.ts
@@ -0,0 +1,80 @@
+import { describe, it, expect, vi } from 'vitest';
+import { render, screen } from '@testing-library/svelte';
+import { userEvent } from '@testing-library/user-event';
+import RecipePickerDrawer from './RecipePickerDrawer.svelte';
+
+const baseProps = {
+ open: true,
+ slotDate: '2026-04-14',
+ planId: 'plan-1',
+ suggestions: [],
+ allRecipes: [
+ { id: 'r1', name: 'Pasta Bolognese', cookTimeMin: 45, effort: 'mittel' },
+ { id: 'r2', name: 'Lachs', cookTimeMin: 20, effort: 'einfach' }
+ ],
+ isLoading: false,
+ onpick: vi.fn(),
+ onclose: vi.fn()
+};
+
+describe('RecipePickerDrawer', () => {
+ describe('visibility', () => {
+ it('renders drawer content when open=true', () => {
+ render(RecipePickerDrawer, { props: baseProps });
+ expect(screen.getByTestId('recipe-picker-drawer')).toBeTruthy();
+ });
+
+ it('drawer is not visible when open=false', () => {
+ render(RecipePickerDrawer, { props: { ...baseProps, open: false } });
+ const drawer = screen.getByTestId('recipe-picker-drawer');
+ // Drawer exists in DOM but should be off-screen / aria-hidden
+ expect(drawer.getAttribute('aria-hidden')).toBe('true');
+ });
+
+ it('renders recipe list inside drawer', () => {
+ render(RecipePickerDrawer, { props: baseProps });
+ expect(screen.getByText('Pasta Bolognese')).toBeTruthy();
+ });
+ });
+
+ describe('backdrop', () => {
+ it('renders backdrop when open', () => {
+ render(RecipePickerDrawer, { props: baseProps });
+ expect(screen.getByTestId('drawer-backdrop')).toBeTruthy();
+ });
+
+ it('calls onclose when backdrop is clicked', async () => {
+ const onclose = vi.fn();
+ const user = userEvent.setup();
+ render(RecipePickerDrawer, { props: { ...baseProps, onclose } });
+ await user.click(screen.getByTestId('drawer-backdrop'));
+ expect(onclose).toHaveBeenCalledOnce();
+ });
+ });
+
+ describe('close button', () => {
+ it('renders a close button inside the drawer', () => {
+ render(RecipePickerDrawer, { props: baseProps });
+ expect(screen.getByRole('button', { name: /schließen|close/i })).toBeTruthy();
+ });
+
+ it('calls onclose when close button clicked', async () => {
+ const onclose = vi.fn();
+ const user = userEvent.setup();
+ render(RecipePickerDrawer, { props: { ...baseProps, onclose } });
+ await user.click(screen.getByRole('button', { name: /schließen|close/i }));
+ expect(onclose).toHaveBeenCalledOnce();
+ });
+ });
+
+ describe('recipe picking', () => {
+ it('calls onpick when a recipe is selected', async () => {
+ const onpick = vi.fn();
+ const user = userEvent.setup();
+ render(RecipePickerDrawer, { props: { ...baseProps, onpick } });
+ const pickButtons = screen.getAllByRole('button', { name: /Wählen/i });
+ await user.click(pickButtons[0]);
+ expect(onpick).toHaveBeenCalledOnce();
+ });
+ });
+});