Patterns
Ask users for date and time
Asking users for date and time is often solved in a more complicated way than necessary. In many situations, standard input fields are both faster to use and easier to understand than custom-built date pickers.
This article has been developed by the design system team at The Norwegian Digitalisation Agency in collaboration with Brønnøysundregistrene. It has not gone through the same collaborative process as the patterns in the Pattern collaboration. We would like feedback on the article. Please share it in Slack or in this discussion thread on github.com.
How you ask users for date and time should be based on the information you actually need. Some dates are easy to remember, such as a date of birth, while others must be read from documents or cards. In some situations, an approximate date is sufficient, or a date relative to today. In other cases, users need to choose a date or time from a predefined set of options.
Avoid making the task more complicated than necessary. Custom-built date pickers often result in lower accessibility and more friction than simple text fields. They can be difficult to use with a keyboard, provide poor support for screen readers, and require unnecessary navigation when the user already knows the date.
Known dates
When asking for well-known dates, such as a date of birth or wedding date, simple text inputs work well. Users already know the answer and often prefer to type it directly, rather than navigating through a calendar.
Consider splitting the date into separate fields for day, month and year. This makes it easier to enter the date correctly and provides better support for assistive technologies. When asking users to enter a date exactly as it appears on a bank card, passport or other document, the fields should match the format shown in that document. This makes it easier to transfer the date accurately and reduces the risk of errors.
React
Unable to parse html
const KnownDatesEN = () => { return ( <Fieldset> <Fieldset.Legend data-size='lg'>When were you born?</Fieldset.Legend> <Fieldset.Description>For example 24 7 1987</Fieldset.Description> <div style={{ display: 'flex', gap: 'var(--ds-size-6)' }}> <Textfield label='Day' style={{ maxWidth: '3.5em' }} autoComplete='bday-day' inputMode='numeric' pattern='[0-9]*' maxLength={2} /> <Textfield label='Month' style={{ maxWidth: '3.5em' }} autoComplete='bday-month' inputMode='numeric' pattern='[0-9]*' maxLength={2} /> <Textfield label='Year' style={{ maxWidth: '6.5em' }} autoComplete='bday-year' inputMode='numeric' pattern='[0-9]*' maxLength={4} /> </div> </Fieldset> ); }; render(<KnownDatesEN />)
In the example above, we use inputmode="numeric" to provide a numeric keyboard on mobile phones and tablets. We deliberately avoid using type="number" for day, month and year fields. type="number" is designed for numeric values that can be incremented or decremented, and introduces functionality such as spin buttons and automatic validation that is not always appropriate for dates. It can also create accessibility issues (mozilla.org), including problems for screen reader users and unintended value changes.
Date from a predefined set of options
If you know that users need to choose a date or time from a limited set of options, for example available appointments in the coming week, it may be more efficient to present these as ready-made choices.
When the number of options is very limited, such as a few dates or times, Radio can be a good choice. It allows users to quickly select an option without having to type anything.
React
Unable to parse html
const PredefinedOptions1EN = () => { return ( <Fieldset> <Fieldset.Legend>When would you like an appointment?</Fieldset.Legend> <Fieldset.Description> Choose from the next five available appointments, or select a later time. </Fieldset.Description> <Radio label='Tuesday 17 Feb at 10:00' value='2026-02-17T10:00' name='appointmentTime' /> <Radio label='Tuesday 17 Feb at 14:00' value='2026-02-17T14:00' name='appointmentTime' /> <Radio label='Friday 20 Feb at 13:30' value='2026-02-20T13:30' name='appointmentTime' /> <Radio label='Monday 23 Feb at 08:00' value='2026-02-23T08:00' name='appointmentTime' /> <Radio label='Monday 23 Feb at 08:30' value='2026-02-23T08:30' name='appointmentTime' /> <Link href='#la-brukeren-begrense-utvalget' style={{ display: 'flex', marginTop: 'var(--ds-size-6)' }} > Find available appointments further ahead </Link> </Fieldset> ); }; render(<PredefinedOptions1EN />)
Let users narrow down the options
When the number of options increases, a Select can be useful to narrow down the list. Users can choose preferred weeks, days or time ranges, and then see the available options based on that selection.
Note: The example below is not connected to an actual data source. It illustrates how users can narrow down the options before seeing the available appointments.
React
Unable to parse html
const PredefinedOptions2EN = () => { return ( <Fieldset> <Fieldset.Legend data-size='lg'> When would you like an appointment? </Fieldset.Legend> <Fieldset.Description> If some weeks are not available, it means there are no free appointments that week. If you prefer Tuesdays, you can choose a weekday instead of a week. You will then see all available appointments on Tuesdays going forward. </Fieldset.Description> <div style={{ display: 'flex', gap: 'var(--ds-size-6)', flexWrap: 'wrap' }} > <Field> <Label>Select preferred week</Label> <Select defaultValue=''> <Select.Option value='' disabled> Select a week … </Select.Option> <Select.Option value='week8'> Week 8 (16 Feb – 22 Feb) </Select.Option> <Select.Option value='week9'> Week 9 (23 Feb – 1 March) </Select.Option> <Select.Option value='week10'> Week 10 (2 March – 8 March) </Select.Option> <Select.Option value='week11'> Week 11 (9 March – 15 March) </Select.Option> <Select.Option value='week12'> Week 12 (16 March – 22 March) </Select.Option> <Select.Option value='week14'> Week 14 (30 March – 5 April) </Select.Option> <Select.Option value='week15'> Week 15 (6 April – 12 April) </Select.Option> <Select.Option value='week16'> Week 16 (13 April – 19 April) </Select.Option> </Select> </Field> <Field> <Label>Select preferred day</Label> <Select defaultValue='Tuesday'> <Select.Option value='' disabled> Select a day … </Select.Option> <Select.Option value='Monday'>Monday</Select.Option> <Select.Option value='Tuesday'>Tuesday</Select.Option> <Select.Option value='Wednesday'>Wednesday</Select.Option> <Select.Option value='Thursday'>Thursday</Select.Option> <Select.Option value='Friday'>Friday</Select.Option> </Select> </Field> <Field> <Label>Select preferred time range</Label> <Select defaultValue=''> <Select.Option value='' disabled> Select a time range … </Select.Option> <Select.Option value='08-11'>08:00 to 11:00</Select.Option> <Select.Option value='11-14'>11:00 to 14:00</Select.Option> <Select.Option value='14-17'>14:00 to 17:00</Select.Option> <Select.Option value='17-20'>17:00 to 20:00</Select.Option> </Select> </Field> </div> <Fieldset style={{ marginTop: 'var(--ds-size-6)' }}> <Fieldset.Legend>Select one of the available times</Fieldset.Legend> <Radio label='Tuesday 17 Feb at 10:00' value='2026-02-17T10:00' name='appointmentTime' /> <Radio label='Tuesday 17 Feb at 14:00' value='2026-02-17T14:00' name='appointmentTime' /> <Radio label='Tuesday 24 Feb at 08:00' value='2026-02-24T08:00' name='appointmentTime' /> <Radio label='Tuesday 24 Feb at 09:30' value='2026-02-24T09:30' name='appointmentTime' /> <Radio label='Tuesday 3 March at 12:30' value='2026-03-03T12:30' name='appointmentTime' /> </Fieldset> </Fieldset> ); }; render(<PredefinedOptions2EN />)
You should only show options that have available appointments, and avoid disabling weeks without availability, as this may create confusion. Explain in advance that only weeks with available times are shown, so users understand why some weeks are not available to select.
Specific date in the near future or past
In some cases, when users need to choose a specific date close to today, visual support can be helpful. An Input with type="date" allows users to either enter the date directly or use the browser's built-in date picker. This often provides a good balance between flexibility and support.
Support varies between browsers and devices in terms of functionality, appearance and interaction, but the solution is often more accessible and robust than custom-built alternatives.
React
Unable to parse html
const NearFuturePastEN = () => { return ( <Textfield label='When should the submission deadline be?' type='date' style={{ maxWidth: '14em' }} /> ); }; render(<NearFuturePastEN />)
Be aware that type="date" is controlled by the user's operating system and regional settings, not by the language of the website. This can result in the date being displayed in a format the user does not expect. Consider whether additional clarity is needed, for example by displaying the selected date in plain text with the month written out in words, or by otherwise asking the user to confirm the date before it is saved.
Start and end date
When users need to provide a period, the start date and end date should be clearly shown together. Use two separate fields and make it clear which date is which.
Place the fields in a logical order and validate that the end date is not earlier than the start date. If the dates depend on each other, error messages should explain what is wrong and how the user can correct it.
React
Unable to parse html
const StartEndDateEN = () => { return ( <Fieldset> <Fieldset.Legend data-size='lg'> How long will you be away? </Fieldset.Legend> <Fieldset.Description>Enter start and end date</Fieldset.Description> <div style={{ display: 'flex', gap: 'var(--ds-size-6)' }}> <Textfield label='Start date' type='date' /> <Textfield label='End date' type='date' /> </div> </Fieldset> ); }; render(<StartEndDateEN />)
Time - start and end
When users need to provide a time interval, such as opening hours or the duration of a meeting, an Input with type="time" can be used. It allows users to enter the time directly, while the browser provides additional support.
Use separate fields for start and end time, and display them clearly together.
React
Unable to parse html
const StartEndTimeEN = () => { return ( <Fieldset> <Fieldset.Legend data-size='lg'> How long does the school day last? </Fieldset.Legend> <Fieldset.Description>Enter start and end time</Fieldset.Description> <div style={{ display: 'flex', gap: 'var(--ds-size-6)' }}> <Textfield label='From' type='time' /> <Textfield label='To' type='time' /> </div> </Fieldset> ); }; render(<StartEndTimeEN />)
Approximate date
If users only need to provide month and year, they should be able to do exactly that. This is particularly relevant when the event took place a long time ago and users may not know the exact date.
For example, you can allow users to enter an approximate date in a free text field, or provide separate fields for month and year only, as shown in the example below.
React
Unable to parse html
const ApproximateDateEN = () => { return ( <Fieldset> <Fieldset.Legend data-size='lg'> When did the event occur? </Fieldset.Legend> <Fieldset.Description> Enter an approximate date. We cannot process cases more than 20 years back. </Fieldset.Description> <div style={{ display: 'flex', gap: 'var(--ds-size-6)' }}> <Field> <Label>Month</Label> <Select defaultValue='January'> <Select.Option value='january'>January</Select.Option> <Select.Option value='february'>February</Select.Option> <Select.Option value='march'>March</Select.Option> <Select.Option value='april'>April</Select.Option> <Select.Option value='may'>May</Select.Option> <Select.Option value='june'>June</Select.Option> <Select.Option value='july'>July</Select.Option> <Select.Option value='august'>August</Select.Option> <Select.Option value='september'>September</Select.Option> <Select.Option value='october'>October</Select.Option> <Select.Option value='november'>November</Select.Option> <Select.Option value='december'>December</Select.Option> </Select> </Field> <Field> <Label>Year</Label> <Select defaultValue='2026'> <Select.Option value='2026'>2026</Select.Option> <Select.Option value='2025'>2025</Select.Option> <Select.Option value='2024'>2024</Select.Option> <Select.Option value='2023'>2023</Select.Option> <Select.Option value='2022'>2022</Select.Option> <Select.Option value='2021'>2021</Select.Option> <Select.Option value='2020'>2020</Select.Option> <Select.Option value='2019'>2019</Select.Option> <Select.Option value='2018'>2018</Select.Option> <Select.Option value='2017'>2017</Select.Option> <Select.Option value='2016'>2016</Select.Option> <Select.Option value='2015'>2015</Select.Option> <Select.Option value='2014'>2014</Select.Option> <Select.Option value='2013'>2013</Select.Option> <Select.Option value='2012'>2012</Select.Option> <Select.Option value='2011'>2011</Select.Option> <Select.Option value='2010'>2010</Select.Option> <Select.Option value='2009'>2009</Select.Option> <Select.Option value='2008'>2008</Select.Option> <Select.Option value='2007'>2007</Select.Option> <Select.Option value='2006'>2006</Select.Option> </Select> </Field> </div> </Fieldset> ); }; render(<ApproximateDateEN />)
Date relative to another date
In some situations, it is more natural to ask for dates relative to another date, for example when setting up a reminder. In these cases, it may be better to use a Select to offer options such as “tomorrow”, “in 3 days” or “1 day before”. If the day of the week is important for the task, it should also be clearly displayed.
React
Unable to parse html
const RelativeDateEN = () => { return ( <Field> <Label>When would you like a reminder?</Label> <Select defaultValue='1 day before'> <Select.Option value='15 minutes before'> 15 minutes before </Select.Option> <Select.Option value='30 minutes before'> 30 minutes before </Select.Option> <Select.Option value='1 hour before'>1 hour before</Select.Option> <Select.Option value='2 hours before'>2 hours before</Select.Option> <Select.Option value='1 day before'>1 day before</Select.Option> <Select.Option value='2 days before'>2 days before</Select.Option> <Select.Option value='3 days before'>3 days before</Select.Option> <Select.Option value='1 week before'>1 week before</Select.Option> </Select> </Field> ); }; render(<RelativeDateEN />)
Summary
Start with the need and choose the solution that allows users to complete the task as quickly as possible. Standard text fields are often more accessible and faster to use than advanced date pickers.
- Show ready-made options when the alternatives are limited
- Let users type when the answer is known
- Only ask for as precise a date and time as the situation requires
- Use built-in browser support rather than custom-built solutions
Sources and relevant information
- Who needs a JavaScript date picker? (dbushell.com)
- Maybe You Don't Need a Date Picker (adrianroselli.com)
- Ask users for dates (gov.uk)