expo-year-month-picker
v1.0.5
Published
A simple year and month picker for React Native.
Maintainers
Readme
expo-year-month-picker
A smooth, high-performance Year and Month picker for React Native, optimized for Expo.
https://github.com/user-attachments/assets/9109c3c1-4b0e-488b-a830-02071ccd3681
Features
- 🚀 High Performance: Built with
react-native-reanimatedandreact-native-gesture-handlerfor butter-smooth 60 FPS interactions. - ✨ Beautiful Design: Features built-in glassmorphism (BlurView) and gradient masking for a premium aesthetic.
- 📱 Native Interactions: Supports drag-to-dismiss gestures and elastic scrolling.
- 🎨 Highly Customizable: Fully controlled component, easy to integrate into any design system.
- 🧩 Isolated & Clean: ZERO dependencies on specific UI frameworks or global states.
Installation
# Using pnpm
pnpm add expo-year-month-picker
# Using npm
npm install expo-year-month-picker
### Peer Dependencies
This package requires the following libraries. Ensure they are installed in your project:
- `react-native-reanimated`
- `react-native-gesture-handler`
- `react-native-safe-area-context`
- `react-native-screens`
- `expo-blur`
- `expo-haptics`
- `expo-symbols`
- `expo-linear-gradient`
- `nativewind`
- `tailwindcss`
- `@react-native-masked-view/masked-view`
## NativeWind Configuration
Since this component uses NativeWind for styling, you **MUST** add the package's source path to your `tailwind.config.js` for styles to be compiled correctly:
```js
// tailwind.config.js
module.exports = {
content: [
"./App.{js,jsx,ts,tsx}",
"./src/**/*.{js,jsx,ts,tsx}",
// ADD THIS LINE
"./node_modules/expo-year-month-picker/src/**/*.{js,jsx,ts,tsx}",
],
presets: [require("nativewind/preset")],
// ... other configs
};Quick Start
import * as Haptics from 'expo-haptics';
import React, { useMemo, useState } from 'react';
import { Pressable, Text, View } from 'react-native';
import {
getMonthName,
type MonthInfo,
YearMonthPicker,
} from 'expo-year-month-picker';
const Example = () => {
const [isVisible, setIsVisible] = useState(false);
const [selectedDate, setSelectedDate] = useState({
year: new Date().getFullYear(),
month: new Date().getMonth() + 1,
});
// Generate available years (e.g., from 1970 to now)
const availableYears = useMemo(() => {
const years = [];
const currentYear = new Date().getFullYear();
for (let i = currentYear; i >= 1970; i--) {
years.push(i);
}
return years;
}, []);
// Generate months for each year
const availableMonthsByYear = useMemo(() => {
const map = new Map<number, MonthInfo[]>();
availableYears.forEach((year) => {
const months: MonthInfo[] = [];
for (let m = 1; m <= 12; m++) {
months.push({
month: m,
name: getMonthName(m, true), // Short names: Jan, Feb, etc.
});
}
map.set(year, months);
});
return map;
}, [availableYears]);
const handleConfirm = (year: number, month: number) => {
setSelectedDate({ year, month });
// not need to close the picker manually, the component will close it by 'onClose' callback after animation
};
const fireHaptic = () => {
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
};
return (
<View className='flex-1 items-center justify-center'>
<Pressable
onPress={() => setIsVisible(true)}
className='px-8 py-4 bg-black dark:bg-white rounded-full active:opacity-70'
>
<Text className='text-white dark:text-black font-bold text-xl'>
{selectedDate.year} . {selectedDate.month.toString().padStart(2, '0')}
</Text>
</Pressable>
{isVisible && (
<YearMonthPicker
isVisible={isVisible}
onClose={() => setIsVisible(false)}
initialYear={selectedDate.year}
initialMonth={selectedDate.month}
availableYears={availableYears}
availableMonthsByYear={availableMonthsByYear}
onConfirm={handleConfirm}
fireHaptic={fireHaptic}
/>
)}
</View>
);
};
export default Example;API Reference
YearMonthPicker Props
| Prop | Type | Description |
| :---------------------- | :-------------------------------------- | :----------------------------------------------------------------------- |
| isVisible | boolean | Controls the visibility of the picker. |
| onClose | () => void | Triggered when the picker requests to close (backdrop tap or pull down). |
| initialYear | number | The initially selected year. |
| initialMonth | number \| null | The initially selected month (1-12). |
| availableYears | number[] | List of years available for selection. |
| availableMonthsByYear | Map<number, MonthInfo[]> | Map of available months for each year. |
| onConfirm | (year: number, month: number) => void | Callback triggered when the confirm button is pressed. |
| fireHaptic | () => void | (Optional) Callback triggered during scroll for haptic feedback. |
Helper Functions
getMonthName(month: number, short?: boolean): Get the English month name.
License
MIT License
