diff --git a/web/src/lib/components/TrackMenuItem.svelte b/web/src/lib/components/TrackMenuItem.svelte
new file mode 100644
index 00000000..d7c2377e
--- /dev/null
+++ b/web/src/lib/components/TrackMenuItem.svelte
@@ -0,0 +1,43 @@
+
+
+
diff --git a/web/src/lib/components/TrackMenuItem.test.ts b/web/src/lib/components/TrackMenuItem.test.ts
new file mode 100644
index 00000000..eddee16b
--- /dev/null
+++ b/web/src/lib/components/TrackMenuItem.test.ts
@@ -0,0 +1,27 @@
+import { describe, test, expect, vi } from 'vitest';
+import { render, fireEvent, screen } from '@testing-library/svelte';
+import { Music2 } from 'lucide-svelte';
+import TrackMenuItem from './TrackMenuItem.svelte';
+
+describe('TrackMenuItem', () => {
+ test('renders icon, label, and fires onclick', async () => {
+ const onclick = vi.fn();
+ render(TrackMenuItem, { props: { icon: Music2, label: 'Play next', onclick } });
+ const btn = screen.getByRole('menuitem', { name: /play next/i });
+ await fireEvent.click(btn);
+ expect(onclick).toHaveBeenCalledOnce();
+ expect(btn.getAttribute('aria-disabled')).toBe('false');
+ });
+
+ test('aria-disabled blocks onclick and reflects in DOM', async () => {
+ const onclick = vi.fn();
+ render(TrackMenuItem, {
+ props: { icon: Music2, label: 'Add to playlist…', onclick, disabled: true, title: 'Coming with playlists' },
+ });
+ const btn = screen.getByRole('menuitem', { name: /add to playlist/i });
+ expect(btn.getAttribute('aria-disabled')).toBe('true');
+ expect(btn.getAttribute('title')).toBe('Coming with playlists');
+ await fireEvent.click(btn);
+ expect(onclick).not.toHaveBeenCalled();
+ });
+});