birthdaypicker
Version:
i18n birthday picker with a variety of setting options
671 lines (561 loc) • 18.3 kB
Markdown
<a name="readme-top"></a>
<!-- PROJECT SHIELDS -->
[![MIT License][license-shield]][license-url]
![min coverage][mincoverage-shield]
[![LinkedIn][linkedin-shield]][linkedin-url]
<!-- PROJECT LOGO -->
<br />
<div align="center">
<a href="https://github.com/lemon3/birthdaypicker">
<img src="https://raw.githubusercontent.com/lemon3/birthdaypicker/main/_assets/images/logo.svg" alt="Logo" width="360" height="auto">
</a>
<h3 align="center">A highly customizable JavaScript birthday picker</h3>
<p>... with support for multiple languages (i18n), date formats, offering a wide range of setting options to suit your application's needs."</p>
<a href="https://lemon3.github.io/birthdaypicker/">BirthdayPicker Demo</a>
<br>
<br>
</div>
<!-- TABLE OF CONTENTS -->
<details>
<summary>Table of Contents</summary>
<ol>
<li>
<a href="#about-the-project">About The Project</a>
</li>
<li>
<a href="#usage">Usage</a>
</li>
<li>
<a href="#api">Api</a>
</li>
<li>
<a href="#getting-started">Getting Started</a>
</li>
<li>
<a href="#license">License</a>
</li>
<li>
<a href="#contact">Contact</a>
</li>
</ol>
</details>
## tl;dr
**modern (module):**
```Bash
pnpm add birthdaypicker
```
```html
<div id="my-div"></div>
```
```js
import BirthdayPicker from 'birthdaypicker';
const options {}; // options (see below)
const bp = new BirthdayPicker('#my-div', options);
```
**classic:**
complete example:
```html
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>demo</title>
</head>
<body>
<div id="my-div"></div>
<script src="https://unpkg.com/birthdaypicker"></script>
<script>
const mbp = new BirthdayPicker('#my-div');
</script>
</body>
</html>
```
<!-- ABOUT THE PROJECT -->
## About The Project
I needed a birthday input field that is easy to use and without JS dependencies. "Simple" in this context means: with as few clicks as possible to the result!
### Features
* Coded in vanilla JS.
* Internationalization (i18n)
* change the language on the fly
* BirthdayPicker is dependency-free ;)
**[BirthdayPicker Demo >>](https://lemon3.github.io/birthdaypicker/)**
<p align="right">(<a href="#readme-top">back to top</a>)</p>
<!-- USAGE EXAMPLES -->
## Usage
### First Steps
#### module js approach
use pnpm / npm / yarn to install the package
```Bash
pnpm add birthdaypicker
```
or:
```Bash
npm install birthdaypicker
```
or:
```Bash
yarn add birthdaypicker
```
and then us it with
```html
<div id="my-div"></div>
```
```js
import BirthdayPicker from 'birthdaypicker';
const options = {}
const bp = new BirthdayPicker('#my-div', options);
```
#### classic js approach
if you use the classic js approach by loading scripts in html code, just download and integrate the **birthdaypicker.umd.js** script in your code:
```html
<div id="my-div"></div>
<script src="https://unpkg.com/birthdaypicker"></script>
<script>
const options = {}
const bp = new BirthdayPicker('#my-div', options);
</script>
```
### Examples via data API
#### html:
```html
<!-- with default values -->
<div data-birthdaypicker></div>
<!-- with current date -->
<div data-birthdaypicker="{ 'defaultDate': 'now' }"></div>
<!-- with arrangement set to: day | month | year -->
<div data-birthdaypicker="{ 'arrange': 'dmy' }"></div>
<!-- using multiple values -->
<div data-birthdaypicker="{
'locale': 'fr',
'defaultDate': 'now',
'arrange':'dmy'
}"></div>
<!-- using the settings string -->
<div data-birthdaypicker="locale:fr,defaultDate:now"></div>
```
**Don't forget to call the init function if using the data API**.
```html
<script>
// initializes all elements
// with following attribute: data-birthdaypicker
BirthdayPicker.init();
</script>
```
### Example via data API (select boxes in DOM)
Select-boxes boxes must be inside the main container (where the **data-birthdaypicker** attribute is defined)!
If the data attributes are set to the select-boxes, the plugin knows which box should be used for what.
Correct syntax for the data attributes (select element):
- year: data-birthdaypicker-year
- month: data-birthdaypicker-month
- day: data-birthdaypicker-day
This scenario (select-boxes in DOM) works best with [tailwindcss](https://tailwindcss.com/), as the select-boxes can be styled with classes here.
| :memo: INFO |
| :---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| If select-boxes already exist in the DOM you cannot use the **arrange** option, eg.: { arrange: 'dmy' }, as this plugin doesn't rearrange existing Elements |
#### 1) with special data attribute on the select boxes
html
```html
<div data-birthdaypicker>
<select data-birthdaypicker-year></select>
<select data-birthdaypicker-month></select>
<select data-birthdaypicker-day></select>
</div>
```
... or use with specified selectors (these selectors take precedence over the data attribute values like **data-birthdaypicker-year**)
#### 2) with id's
html
```html
<!-- yearEl, monthEl and dayEl must be a regular querySelector! -->
<div data-birthdaypicker="{
'yearEl':'#myYear',
'monthEl':'#myMonth',
'dayEl':'.myDay'
}">
<select id="myYear"></select>
<select id="myMonth"></select>
<select class="myDay"></select>
</div>
```
#### 2) with just 'blank' select boxes
html
```html
<div data-birthdaypicker="{'arrange':'dmy'}">
<select></select> <!-- day -->
<select></select> <!-- month -->
<select></select> <!-- year -->
</div>
```
**Don't forget to call the init function if using the data API**.
```html
<script>
// initializes all found BirthdayPicker
// looking for [data-birthdaypicker]
BirthdayPicker.init();
</script>
```
### Example via js
#### js Example #1
just a div, js does the "magic"!
```html
<!-- initialized with default values -->
<div id="bp1"></div>
<!-- initialized with custom options (see below) -->
<div id="bp2"></div>
<script src="https://unpkg.com/birthdaypicker"></script>
<script>
// initialize with default values
const bp1 = new BirthdayPicker('#bp1');
// initialize with current date (new Date(), or 'now')
// see 'option API' section for all available options
const bp2 = new BirthdayPicker('#bp2', {
defaultDate: new Date()
});
</script>
```
#### js Example #2
html file with defined select boxes.
Reference these in the options object.
```html
<div id="bp1">
<select id="myYear"></select>
<select id="myMonth"></select>
<select id="myDay"></select>
</div>
<script src="https://unpkg.com/birthdaypicker"></script>
<script>
const bp1 = new BirthdayPicker('#bp1', {
yearEl: '#myYear',
monthEl: '#myMonth',
dayEl: '#myDay',
// ... other options
});
</script>
```
<p align="right">(<a href="#readme-top">back to top</a>)</p>
## API
### initialize
```js
// element: a dom reference to one element, or a querySelector string
const element = '#my-div';
// an options-object, see below
const options = {};
const myBirthdayPicker = new BirthdayPicker(element, options);
```
### API / options
```js
options = {
// sets the minimal age for a person, animal,...
// if set > 0 it changes the maximal selectable year by it's value
// e.g.: maxYear: 2022, minAge: 10 -> max selectable year: 2012!
// default: 0
// example: 10
minAge: 0,
// sets the maximal age for a person, animal,...
// min selectable year is 1922 if maxYear is 2022 (2022 - 100)
// default: 100,
maxAge: 100,
// sets the minimal year (overrides maxAge)
// default: null
// example: 1980
minYear: null,
// sets the maximal year
// default: '(new Date()).getFullYear()'
// example: 2040 | 'now'
maxYear: 'now',
// coming soon
lowerLimit: null,
// coming soon
upperLimit: null,
// sets the month format for the select box
// available: 'short', 'long', 'numeric'
// default: 'short'
monthFormat: 'short',
// shows a placeholder for each select box
// available: true | false
// default: true
placeholder: true,
// if set, name will be added to each select box
// and [name]-year [name]-month [name]-day (will be added too)
// where name is the className chosen.
// e.g.: 'my-class' results in:
// <select class="my-class my-class-year"></select>
className: null,
// sets the selected start date
// available: 'now' | new Date() | '2020-10-12' (YYYY-MM-DD)
// default: null
// example: '2012-12-04'
defaultDate: null,
// if the init method should be called on creating an instance:
// const myBp = new BirthdayPicker(el, {})
// if set to false, you have to call myBp.init() afterwards.
// available: true | false
// default: true
autoInit: true,
// if the month and day values in the select-box should have a leading
// zero or not. If set to true, you will get: 01, 02, 03, ... 10, 11, ...
// if set to false, you will get: 1, 2, 3, ... 10, 11, ...
// available: true | false
// default: true
leadingZero: true,
// sets the language to be used
// available: 'en', 'de', 'fr', ... all country codes with 2chars (ISO 3166-1 alpha-2)
// default: 'en'
locale: 'en',
// if it should be possible to select a 'future' date
// false means: unable to select a date in the future
// available: true | false
// default: false
selectFuture: false,
// to arrange the select-boxes
// y: year, m: month, d: day
// so ymd means: year | month | day
// ordering is only available, if select boxes are not present in the DOM
// available: 'ymd', 'ydm', 'myd', 'mdy', 'dmy', 'dym'
// default: 'ymd'
arrange: 'ymd',
// specify a custom select-box for the year
// must be inside the main element
// all valid query-strings allowed
// available: null, valid query-strings (querySelector), or html reference
// default: null
// example: '#my-year-select'
yearEl: null,
// specify a custom select-box for the month
// must be inside the main element
// all valid query-strings allowed
// available: null, valid query-strings (querySelector), or html reference
// default: null
// example: '#my-month-select'
monthEl: null,
// specify a custom select-box for the day
// must be inside the main element
// all valid query-strings allowed
// available: null, valid query-strings (querySelector), or html reference
// default: null
// example: '#my-day-select'
dayEl: null,
// sets days to highest possible value, if the month (or in special cases
// the year) is changed and the current selected day-value is higher than
// the possible value for the new month (year).
// true: rounds down
// false: returns undefined for the day (so nothing is selected)
// available: true | false
// default: true
//
// Example:
// Current date is 2024-02-29 (yyyy-mm-dd)
// set year back to 2023
// if roundDownDay is true: day will be: 28
// if roundDownDay is false: day will be: undefined
roundDownDay: true
};
```
### API / methods
```js
const element = '#my-div';
const options = {
autoInit: false
};
const myBirthdayPicker = new BirthdayPicker(element, options);
// init: initializes the picker
myBirthdayPicker.init();
// getDate returns the current selected date with the language default date-formatting!
// you can change the format, by calling the method with a specific date-format value.
// e.g.: 'yyyy-m-d'
// if date is 2. Sep. 1994
// return values are:
// 'yy' -> 94
// 'yyyy' -> 1994
// 'mm' -> 09
// 'm' -> 9
// 'dd' -> 02
// 'd' -> 2
myBirthdayPicker.getDateString('yyyy-m-d');
// returns a Date object (like new Date())
// for the current year, month, day values
myBirthdayPicker.getDate();
// returns the age of the subject (person)
myBirthdayPicker.getAge();
// just a small helper method, returns true or false
myBirthdayPicker.isLeapYear(2020); // true
// listen to different events eg.
// available events: init | datechange
const myEventListener = () => {};
myBirthdayPicker.addEventListener('datechange', myEventListener, false);
// remove the event listener
myBirthdayPicker.removeEventListener('datechange', myEventListener);
// set the date to a given value
// e.g.: '2020-10-22' // yyyy-mm-dd: this is the 22. oct. 2020
// or to the current date with new Date()
myBirthdayPicker.setDate(new Date());
// resets the date
// true: resets to the defaultDate (start date);
// false: all select boxes will be reset to default value (if available)
myBirthdayPicker.resetDate(true);
// sets the language for the current instance
// e.g.: 'en', 'de', 'fr', ...
myBirthdayPicker.setLanguage('en');
// sets the month format for the current instance
// available: 'short', 'long', 'numeric'
myBirthdayPicker.setMonthFormat('short');
// setter, if the
myBirthdayPicker.useLeadingZero(true); // true | false
// kills the current instance and removes all event-listeners
myBirthdayPicker.kill();
```
### API / event-listeners
```js
const element = document.querySelector('#my-element');
const options = {};
const myPicker = new BirthdayPicker(element, options);
// available event listeners
const available = [
'init', // triggered after init
'kill', // triggered when the kill was called
'daychange', // triggered when the day value was changed
'monthchange', // triggered when the month value was changed
'yearchange', // triggered when the year value was changed
'datechange', // triggered when day, month or year value was changed
]
// use the instance as event listener
myPicker.addEventListener('datechange', (evt) => {
// todo something ...
});
// or the element itself
element.addEventListener('datechange', (evt) => {
// todo something ...
});
```
### API / event-listeners (as callback)
inside the option object
```js
const options = {
// ...
datechange: (evt) => { /* do stuff */ },
monthchange: (evt) => { /* do stuff */ },
// ...
};
const myPicker = new BirthdayPicker('#my-element', options);
```
#### example using all event-listener possibilities
see the event sequence!
```js
import BirthdayPicker from 'birthdaypicker';
const options = {
datechange: (evt) => {
console.log('i am: 1st');
},
};
const pickerEl = document.getElementById('my-element');
const picker = new BirthdayPicker(pickerEl, options);
// on instance
picker.addEventListener('datechange', (evt) => {
console.log('i am: 2nd');
});
// on DOM element
pickerEl.addEventListener('datechange', (evt) => {
console.log('i am: 3rd');
});
```
### API / static Methods
#### createLocale()
```js
// used to create a locale object for the selected language
// parameter: (string, required)
// eg.: 'de' | 'en' | 'fr'
// returns an object for the given language (if language not found defaults to english 'en')
// is added to BirthdayPicker.i18n
BirthdayPicker.createLocale('de')
```
#### getInstance()
```js
// returns the instance
// (if the element has previously been initialized with new BirthdayPicker('#myBP')
// returns either the instance ore false
htmlElement = document.getElementById('#myBP');
BirthdayPicker.getInstance(htmlElement)
```
#### setMonthFormat()
```js
// sets the MonthFormat (select boxes) for all instances
// format: 'short' | 'long' | 'numeric'
BirthdayPicker.setMonthFormat('short')
```
#### kill()
```js
// kill all eventListeners
htmlElement = document.getElementById('#myBP');
BirthdayPicker.kill(htmlElement)
```
#### killAll()
```js
// kill all registered instances
BirthdayPicker.killAll()
```
### API / static Properties
```js
// an object with all languages cerated
BirthdayPicker.i18n
// shows the current global language as string (2 chars, e.g.: 'en' | 'de')
BirthdayPicker.currentLocale
```
### Demo
A **small demo** of this tool can be view here: [BirthdayPicker Demo](https://lemon3.github.io/birthdaypicker/)
<p align="right">(<a href="#readme-top">back to top</a>)</p>
<!-- GETTING STARTED -->
## Getting Started
### Prerequisites
you need to have **node** and **pnpm**.
skip to prerequisites if you already have this installed ;)
1. Install node
1. download [download here](https://nodejs.org/en/download/)
2. via brew
```Bash
brew install node
```
2. Install pnpm:
see here: https://pnpm.io/installation
### Installation
1. Clone the repo
```Bash
git clone https://github.com/lemon3/birthdaypicker.git
```
2. cd into the cloned repo
```Bash
cd birthdaypicker
```
3. Install packages
```Bash
pnpm install
```
4. start (dev)
```Bash
pnpm dev
```
To see all available scripts, open the **package.json** file or run
```Bash
pnpm run
```
<p align="right">(<a href="#readme-top">back to top</a>)</p>
<!-- LICENSE -->
## License
Distributed under the MIT License. See `LICENSE.txt` for more information.
<p align="right">(<a href="#readme-top">back to top</a>)</p>
## Roadmap
- be able to define lowerLimit and upperLimit via new Date()
<p align="right">(<a href="#readme-top">back to top</a>)</p>
<!-- CONTACT -->
## Contact
Wolfgang Jungmayer - lemon3.at
Project Link: [https://github.com/lemon3/birthdaypicker](https://github.com/lemon3/birthdaypicker)
<p align="right">(<a href="#readme-top">back to top</a>)</p>
<div align="center">coded with ❤ in vienna<br>by wolfgang jungmayer</div>
<!-- MARKDOWN LINKS & IMAGES -->
[license-shield]: https://img.shields.io/github/license/lemon3/birthdaypicker?style=for-the-badge
[license-url]: https://github.com/lemon3/birthdaypicker/blob/main/LICENSE
[linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=for-the-badge&logo=linkedin&colorB=555
[linkedin-url]: https://www.linkedin.com/in/wolfgangjungmayer/
[mincoverage-shield]: https://img.shields.io/nycrc/lemon3/birthdaypicker?style=for-the-badge
[minified-shield]: https://img.shields.io/github/size/lemon3/birthdaypicker/dist/birthdaypicker.umd.js?label=Minified%20Size&style=for-the-badge
[minified-gzip-shield]: https://img.shields.io/badge/minified%20gzip%20Size-4.7%20KB-blue?style=for-the-badge