diff --git a/app/components/malio/date/internal/YearPicker.test.ts b/app/components/malio/date/internal/YearPicker.test.ts
new file mode 100644
index 0000000..7ee7989
--- /dev/null
+++ b/app/components/malio/date/internal/YearPicker.test.ts
@@ -0,0 +1,36 @@
+import {describe, expect, it} from 'vitest'
+import {mount} from '@vue/test-utils'
+import YearPicker from './YearPicker.vue'
+
+const mountPicker = (props: {pageStart: number, selectedYear?: number, min?: string, max?: string}) =>
+ mount(YearPicker, {props})
+
+describe('MalioDateYearPicker', () => {
+ it('renders 12 years from pageStart', () => {
+ const wrapper = mountPicker({pageStart: 2021})
+ const years = wrapper.findAll('[data-test="year"]')
+ expect(years).toHaveLength(12)
+ expect(years[0].attributes('data-year')).toBe('2021')
+ expect(years[11].attributes('data-year')).toBe('2032')
+ })
+
+ it('emits select with the clicked year', async () => {
+ const wrapper = mountPicker({pageStart: 2021})
+ await wrapper.get('[data-test="year"][data-year="2026"]').trigger('click')
+ expect(wrapper.emitted('select')?.[0]).toEqual([2026])
+ })
+
+ it('disables years outside [min, max] and does not emit', async () => {
+ const wrapper = mountPicker({pageStart: 2021, min: '2025-01-01', max: '2027-12-31'})
+ const out = wrapper.get('[data-test="year"][data-year="2024"]')
+ expect(out.attributes('disabled')).toBeDefined()
+ await out.trigger('click')
+ expect(wrapper.emitted('select')).toBeUndefined()
+ })
+
+ it('highlights the selected year', () => {
+ const wrapper = mountPicker({pageStart: 2021, selectedYear: 2026})
+ const span = wrapper.get('[data-test="year"][data-year="2026"] span')
+ expect(span.classes()).toContain('bg-m-primary')
+ })
+})
diff --git a/app/components/malio/date/internal/YearPicker.vue b/app/components/malio/date/internal/YearPicker.vue
new file mode 100644
index 0000000..f887fb8
--- /dev/null
+++ b/app/components/malio/date/internal/YearPicker.vue
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+