Skip to content
Feature

Validation

Built-in validation with custom rules and error handling

Built-in Validation

Timepicker-UI automatically validates time input and provides feedback for invalid values:

  • Validates time format (HH:mm or hh:mm AM/PM)
  • Checks for valid hour and minute ranges
  • Respects disabled time restrictions
  • Prevents invalid manual input
  • HTML5 time input validation support

Valid Time Detection

Use the accept event to handle valid time selection:

index.tstypescript
1const input = document.querySelector('#timepicker');
2const picker = new TimepickerUI(input);
3
4picker.create();
5
6input.addEventListener('accept', (event) => {
7 const selectedTime = event.detail.hour + ':' + event.detail.minutes;
8 console.log('Valid time selected:', selectedTime);
9
10 // Perform actions with validated time
11 submitForm(selectedTime);
12});

Error Handling

Detect and handle invalid time input:

Invalid Input Detection

index.tstypescript
1const input = document.querySelector('#timepicker');
2const errorMessage = document.querySelector('#error-message');
3
4input.addEventListener('input', (e) => {
5 const value = e.target.value;
6
7 if (!isValidTimeFormat(value)) {
8 errorMessage.textContent = 'Please enter a valid time (HH:mm)';
9 errorMessage.classList.add('visible');
10 } else {
11 errorMessage.classList.remove('visible');
12 }
13});
14
15function isValidTimeFormat(time) {
16 const timeRegex = /^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$/;
17 return timeRegex.test(time);
18}

Disabled Time Validation

index.tstypescript
1const picker = new TimepickerUI(input, {
2 disabledTime: {
3 hours: [0, 1, 2, 3, 4, 5, 22, 23]
4 }
5});
6
7picker.create();
8
9input.addEventListener('accept', (event) => {
10 const hour = event.detail.hour;
11
12 // This will never trigger for disabled hours
13 // as they cannot be selected
14 console.log('Selected hour:', hour);
15});
16
17// Validate manual input
18input.addEventListener('change', (e) => {
19 const [hour] = e.target.value.split(':').map(Number);
20 const disabledHours = [0, 1, 2, 3, 4, 5, 22, 23];
21
22 if (disabledHours.includes(hour)) {
23 e.target.setCustomValidity('This time is not available');
24 e.target.reportValidity();
25 } else {
26 e.target.setCustomValidity('');
27 }
28});

Custom Validation Rules

Implement custom validation logic for specific business requirements:

Minimum Time Validation

index.tstypescript
1function validateMinTime(selectedTime, minTime) {
2 const selected = timeToMinutes(selectedTime);
3 const minimum = timeToMinutes(minTime);
4
5 return selected >= minimum;
6}
7
8function timeToMinutes(time) {
9 const [hours, minutes] = time.split(':').map(Number);
10 return hours * 60 + minutes;
11}
12
13// Usage
14input.addEventListener('accept', (event) => {
15 const time = event.detail.hour + ':' + event.detail.minutes;
16 const minTime = '09:00';
17
18 if (!validateMinTime(time, minTime)) {
19 alert('Please select a time after 9:00 AM');
20 input.value = '';
21 }
22});

Time Range Validation

index.tstypescript
1function isTimeInRange(time, startTime, endTime) {
2 const selected = timeToMinutes(time);
3 const start = timeToMinutes(startTime);
4 const end = timeToMinutes(endTime);
5
6 return selected >= start && selected <= end;
7}
8
9function timeToMinutes(time) {
10 const [hours, minutes] = time.split(':').map(Number);
11 return hours * 60 + minutes;
12}
13
14// Validate on accept
15input.addEventListener('accept', (event) => {
16 const time = event.detail.hour + ':' + event.detail.minutes;
17
18 if (!isTimeInRange(time, '09:00', '17:00')) {
19 showError('Please select a time between 9:00 AM and 5:00 PM');
20 return;
21 }
22
23 submitTime(time);
24});

Date-Time Validation

index.tstypescript
1function validateDateTime(date, time) {
2 const now = new Date();
3 const selected = new Date(date + 'T' + time);
4
5 return selected > now;
6}
7
8// Combined date and time validation
9const dateInput = document.querySelector('#date-picker');
10const timeInput = document.querySelector('#time-picker');
11
12timeInput.addEventListener('accept', (event) => {
13 const time = event.detail.hour + ':' + event.detail.minutes;
14 const date = dateInput.value;
15
16 if (!validateDateTime(date, time)) {
17 showError('Cannot select a time in the past');
18 timeInput.value = '';
19 return;
20 }
21
22 console.log('Valid future date-time:', date, time);
23});

HTML5 Validation

Leverage native HTML5 validation attributes:

Required Time Input

index.htmlhtml
1<form>
2 <label for="timepicker">
3 Meeting Time (Required)
4 </label>
5 <input
6 type="time"
7 id="timepicker"
8 required
9 min="09:00"
10 max="17:00"
11 step="900"
12 />
13 <button type="submit">Schedule</button>
14</form>
15
16<script>
17const picker = new TimepickerUI(
18 document.querySelector('#timepicker')
19);
20picker.create();
21
22document.querySelector('form').addEventListener('submit', (e) => {
23 e.preventDefault();
24
25 if (e.target.checkValidity()) {
26 console.log('Form is valid!');
27 // Submit form
28 } else {
29 console.log('Form has validation errors');
30 }
31});
32</script>

Custom Validation Messages

index.tstypescript
1const input = document.querySelector('#timepicker');
2
3input.addEventListener('invalid', (e) => {
4 e.target.setCustomValidity('Please select a valid time');
5});
6
7input.addEventListener('input', (e) => {
8 // Clear custom message when user starts typing
9 e.target.setCustomValidity('');
10});
11
12// Custom range validation
13input.addEventListener('change', (e) => {
14 const [hours, minutes] = e.target.value.split(':').map(Number);
15 const totalMinutes = hours * 60 + minutes;
16
17 if (totalMinutes < 540) { // Before 9:00 AM
18 e.target.setCustomValidity('Business hours start at 9:00 AM');
19 e.target.reportValidity();
20 } else if (totalMinutes > 1020) { // After 5:00 PM
21 e.target.setCustomValidity('Business hours end at 5:00 PM');
22 e.target.reportValidity();
23 } else {
24 e.target.setCustomValidity('');
25 }
26});

Visual Error States

Style the input to show validation errors:

Error Styling

index.csscss
1/* Input error state */
2input[type="time"]:invalid {
3 border-color: #ef4444;
4 background-color: #fef2f2;
5}
6
7input[type="time"]:invalid:focus {
8 outline-color: #ef4444;
9 box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
10}
11
12/* Error message */
13.error-message {
14 display: none;
15 color: #ef4444;
16 font-size: 0.875rem;
17 margin-top: 0.5rem;
18}
19
20.error-message.visible {
21 display: block;
22}
23
24/* Success state */
25input[type="time"]:valid {
26 border-color: #10b981;
27}

Complete Example

index.htmlhtml
1<div class="form-group">
2 <label for="timepicker">Select time</label>
3 <input
4 type="time"
5 id="timepicker"
6 class="form-control"
7 required
8 />
9 <span class="error-message" id="error"></span>
10</div>
11
12<style>
13.form-control {
14 border: 2px solid #e5e7eb;
15 border-radius: 0.5rem;
16 padding: 0.5rem 0.75rem;
17 transition: all 0.2s;
18}
19
20.form-control.error {
21 border-color: #ef4444;
22}
23
24.form-control.success {
25 border-color: #10b981;
26}
27</style>
28
29<script>
30const input = document.querySelector('#timepicker');
31const errorMsg = document.querySelector('#error');
32
33input.addEventListener('change', () => {
34 if (input.validity.valid) {
35 input.classList.remove('error');
36 input.classList.add('success');
37 errorMsg.textContent = '';
38 } else {
39 input.classList.add('error');
40 input.classList.remove('success');
41 errorMsg.textContent = input.validationMessage;
42 }
43});
44</script>

Server-Side Validation

Always validate time values on your server. Client-side validation improves user experience but can be bypassed. Implement the same validation rules on your backend to ensure data integrity and security.

Learn about events