Skip to content

Time Picker

Overview

The Time Picker component is used for selecting time, supporting various time selection modes including single time and time range selection. It provides rich configuration options and customization features to meet various time selection needs.

Learning Objectives

  • Master the basic concepts and use cases of Time Picker
  • Learn how to implement basic time selection functionality
  • Understand time range selection and time restrictions
  • Master time formatting and display
  • Learn about disabled time and step configuration
  • Understand custom time pickers
  • Master the application of time pickers in real projects
  • Master the complete usage of the API

Basic Usage

Basic Time Selection

The simplest time picker:

vue
<template>
  <div>
    <h4>Basic Time Selection</h4>
    <el-time-picker
      v-model="time1"
      placeholder="Select time"
    />
    <p>Selected time: {{ time1 }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const time1 = ref('')
</script>

Time Range Restriction

Restrict the selectable time range:

vue
<template>
  <div>
    <h4>Time Range Restriction</h4>
    <el-time-picker
      v-model="time2"
      :disabled-hours="disabledHours"
      :disabled-minutes="disabledMinutes"
      :disabled-seconds="disabledSeconds"
      placeholder="Select time"
    />
    <p>Only 9:00-18:00 can be selected</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const time2 = ref('')

const disabledHours = () => {
  const hours = []
  for (let i = 0; i < 9; i++) {
    hours.push(i)
  }
  for (let i = 18; i < 24; i++) {
    hours.push(i)
  }
  return hours
}

const disabledMinutes = (hour) => {
  // No restrictions on minutes during work hours
  return []
}

const disabledSeconds = (hour, minute) => {
  // No restrictions on seconds
  return []
}
</script>

Time Range Selection

Select a time range:

vue
<template>
  <div>
    <h4>Time Range Selection</h4>
    <el-time-picker
      v-model="timeRange"
      is-range
      range-separator="to"
      start-placeholder="Start time"
      end-placeholder="End time"
    />
    <p>Selected time range: {{ timeRange }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const timeRange = ref('')
</script>

Fixed Time Points

Provide fixed time points for selection:

vue
<template>
  <div>
    <h4>Fixed Time Points</h4>
    <el-time-select
      v-model="time3"
      start="08:30"
      step="00:15"
      end="18:30"
      placeholder="Select time"
    />
    <p>Selected time: {{ time3 }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const time3 = ref('')
</script>

Time Formatting

Customize time display format:

vue
<template>
  <div>
    <h4>Time Formatting</h4>
    <el-time-picker
      v-model="time4"
      format="HH:mm:ss"
      value-format="HH:mm:ss"
      placeholder="Select time"
    />
    <p>Formatted time: {{ time4 }}</p>
    
    <el-time-picker
      v-model="time5"
      format="hh:mm:ss A"
      value-format="HH:mm:ss"
      placeholder="12-hour format"
    />
    <p>12-hour format time: {{ time5 }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const time4 = ref('')
const time5 = ref('')
</script>

Advanced Features

Step Settings

Set the step for time selection:

vue
<template>
  <div>
    <h4>Step Settings</h4>
    <div class="step-demo">
      <div class="step-item">
        <label>5-minute step:</label>
        <el-time-select
          v-model="stepTime1"
          start="00:00"
          step="00:05"
          end="23:59"
          placeholder="Select time"
        />
      </div>
      
      <div class="step-item">
        <label>15-minute step:</label>
        <el-time-select
          v-model="stepTime2"
          start="00:00"
          step="00:15"
          end="23:59"
          placeholder="Select time"
        />
      </div>
      
      <div class="step-item">
        <label>30-minute step:</label>
        <el-time-select
          v-model="stepTime3"
          start="00:00"
          step="00:30"
          end="23:59"
          placeholder="Select time"
        />
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const stepTime1 = ref('')
const stepTime2 = ref('')
const stepTime3 = ref('')
</script>

<style scoped>
.step-demo {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.step-item {
  display: flex;
  align-items: center;
  gap: 12px;
}

.step-item label {
  width: 120px;
  font-weight: 500;
  color: #303133;
}
</style>

Disabled State

Disable the time picker:

vue
<template>
  <div>
    <h4>Disabled State</h4>
    <div class="disabled-demo">
      <el-time-picker
        v-model="disabledTime"
        disabled
        placeholder="Disabled state"
      />
      
      <el-time-picker
        v-model="readonlyTime"
        readonly
        placeholder="Read-only state"
      />
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const disabledTime = ref('12:30:00')
const readonlyTime = ref('15:45:30')
</script>

<style scoped>
.disabled-demo {
  display: flex;
  gap: 16px;
  align-items: center;
}
</style>

Different Sizes

Provide time pickers in different sizes:

vue
<template>
  <div>
    <h4>Different Sizes</h4>
    <div class="size-demo">
      <el-time-picker
        v-model="time6"
        size="large"
        placeholder="Large size"
      />
      <el-time-picker
        v-model="time7"
        placeholder="Default size"
      />
      <el-time-picker
        v-model="time8"
        size="small"
        placeholder="Small size"
      />
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const time6 = ref('')
const time7 = ref('')
const time8 = ref('')
</script>

<style scoped>
.size-demo {
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: flex-start;
}
</style>

Clearable

Add clear functionality:

vue
<template>
  <div>
    <h4>Clearable</h4>
    <el-time-picker
      v-model="clearableTime"
      clearable
      placeholder="Clearable time picker"
    />
    <p>Selected time: {{ clearableTime || 'Not selected' }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const clearableTime = ref('')
</script>

Practical Application Examples

Meeting Room Booking Time Selection

Create a time selection component for meeting room booking:

vue
<template>
  <div class="meeting-room-booking">
    <h3>Meeting Room Booking</h3>
    
    <div class="booking-form">
      <div class="form-section">
        <h4>Select Meeting Room</h4>
        <el-select v-model="selectedRoom" placeholder="Please select a meeting room">
          <el-option
            v-for="room in meetingRooms"
            :key="room.id"
            :label="room.name"
            :value="room.id"
          >
            <span>{{ room.name }}</span>
            <span class="room-capacity">({{ room.capacity }} people)</span>
          </el-option>
        </el-select>
      </div>
      
      <div class="form-section">
        <h4>Select Time Slot</h4>
        <div class="time-selection">
          <div class="time-item">
            <label>Start time:</label>
            <el-time-select
              v-model="startTime"
              start="08:00"
              step="00:30"
              end="18:00"
              placeholder="Select start time"
              @change="handleStartTimeChange"
            />
          </div>
          
          <div class="time-item">
            <label>End time:</label>
            <el-time-select
              v-model="endTime"
              :start="minEndTime"
              step="00:30"
              end="18:30"
              placeholder="Select end time"
              :disabled="!startTime"
            />
          </div>
        </div>
        
        <div v-if="duration" class="duration-info">
          <span class="duration-label">Meeting duration:</span>
          <span class="duration-value">{{ duration }}</span>
        </div>
      </div>
      
      <div v-if="selectedRoom && startTime && endTime" class="booking-summary">
        <h4>Booking Information</h4>
        <div class="summary-content">
          <div class="summary-item">
            <span class="label">Meeting room:</span>
            <span class="value">{{ getRoomName(selectedRoom) }}</span>
          </div>
          <div class="summary-item">
            <span class="label">Time:</span>
            <span class="value">{{ startTime }} - {{ endTime }}</span>
          </div>
          <div class="summary-item">
            <span class="label">Duration:</span>
            <span class="value">{{ duration }}</span>
          </div>
          <div class="summary-item">
            <span class="label">Cost:</span>
            <span class="value cost">¥{{ calculateCost() }}</span>
          </div>
        </div>
        
        <div class="booking-actions">
          <el-button type="primary" @click="confirmBooking">Confirm Booking</el-button>
          <el-button @click="resetForm">Reset</el-button>
        </div>
      </div>
    </div>
    
    <div v-if="bookings.length > 0" class="booking-history">
      <h4>Booking History</h4>
      <div class="history-list">
        <div
          v-for="booking in bookings"
          :key="booking.id"
          class="history-item"
        >
          <div class="booking-info">
            <div class="booking-room">{{ getRoomName(booking.roomId) }}</div>
            <div class="booking-time">{{ booking.startTime }} - {{ booking.endTime }}</div>
            <div class="booking-date">{{ formatDate(booking.date) }}</div>
          </div>
          <div class="booking-status">
            <el-tag
              :type="getStatusType(booking.status)"
              size="small"
            >
              {{ booking.status }}
            </el-tag>
            <el-button
              v-if="booking.status === 'Booked'"
              size="small"
              type="danger"
              @click="cancelBooking(booking.id)"
            >
              Cancel
            </el-button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'
import { ElMessage } from 'element-plus'

const selectedRoom = ref('')
const startTime = ref('')
const endTime = ref('')
const bookings = ref([
  {
    id: 1,
    roomId: 1,
    startTime: '09:00',
    endTime: '10:30',
    date: new Date(),
    status: 'Booked'
  },
  {
    id: 2,
    roomId: 2,
    startTime: '14:00',
    endTime: '16:00',
    date: new Date(),
    status: 'Completed'
  }
])

const meetingRooms = ref([
  { id: 1, name: 'Meeting Room A', capacity: 10, hourlyRate: 50 },
  { id: 2, name: 'Meeting Room B', capacity: 20, hourlyRate: 80 },
  { id: 3, name: 'Meeting Room C', capacity: 50, hourlyRate: 150 },
  { id: 4, name: 'Multi-function Hall', capacity: 100, hourlyRate: 300 }
])

const minEndTime = computed(() => {
  if (!startTime.value) return '08:30'
  
  const [hours, minutes] = startTime.value.split(':').map(Number)
  const startMinutes = hours * 60 + minutes + 30 // minimum 30 minutes
  const endHours = Math.floor(startMinutes / 60)
  const endMins = startMinutes % 60
  
  return `${endHours.toString().padStart(2, '0')}:${endMins.toString().padStart(2, '0')}`
})

const duration = computed(() => {
  if (!startTime.value || !endTime.value) return ''
  
  const [startHours, startMinutes] = startTime.value.split(':').map(Number)
  const [endHours, endMinutes] = endTime.value.split(':').map(Number)
  
  const startTotalMinutes = startHours * 60 + startMinutes
  const endTotalMinutes = endHours * 60 + endMinutes
  
  const durationMinutes = endTotalMinutes - startTotalMinutes
  
  if (durationMinutes <= 0) return ''
  
  const hours = Math.floor(durationMinutes / 60)
  const minutes = durationMinutes % 60
  
  if (hours === 0) {
    return `${minutes} minutes`
  } else if (minutes === 0) {
    return `${hours} hours`
  } else {
    return `${hours} hours ${minutes} minutes`
  }
})

const handleStartTimeChange = () => {
  // If end time is less than start time, clear end time
  if (endTime.value && startTime.value >= endTime.value) {
    endTime.value = ''
  }
}

const getRoomName = (roomId) => {
  const room = meetingRooms.value.find(r => r.id === roomId)
  return room ? room.name : 'Unknown Meeting Room'
}

const calculateCost = () => {
  if (!selectedRoom.value || !duration.value) return 0
  
  const room = meetingRooms.value.find(r => r.id === selectedRoom.value)
  if (!room) return 0
  
  const [startHours, startMinutes] = startTime.value.split(':').map(Number)
  const [endHours, endMinutes] = endTime.value.split(':').map(Number)
  
  const startTotalMinutes = startHours * 60 + startMinutes
  const endTotalMinutes = endHours * 60 + endMinutes
  const durationMinutes = endTotalMinutes - startTotalMinutes
  
  const hours = Math.ceil(durationMinutes / 60) // Charged by hour, less than an hour is calculated as one hour
  
  return hours * room.hourlyRate
}

const confirmBooking = () => {
  const newBooking = {
    id: Date.now(),
    roomId: selectedRoom.value,
    startTime: startTime.value,
    endTime: endTime.value,
    date: new Date(),
    status: 'Booked'
  }
  
  bookings.value.unshift(newBooking)
  ElMessage.success('Meeting room booked successfully!')
  resetForm()
}

const resetForm = () => {
  selectedRoom.value = ''
  startTime.value = ''
  endTime.value = ''
}

const cancelBooking = (bookingId) => {
  const booking = bookings.value.find(b => b.id === bookingId)
  if (booking) {
    booking.status = 'Cancelled'
    ElMessage.success('Booking cancelled')
  }
}

const formatDate = (date) => {
  return new Date(date).toLocaleDateString()
}

const getStatusType = (status) => {
  const statusMap = {
    'Booked': 'warning',
    'Completed': 'success',
    'Cancelled': 'danger'
  }
  return statusMap[status] || 'info'
}
</script>

<style scoped>
.meeting-room-booking {
  max-width: 800px;
  padding: 20px;
}

.booking-form {
  background: #f5f7fa;
  padding: 20px;
  border-radius: 8px;
  margin-bottom: 24px;
}

.form-section {
  margin-bottom: 24px;
}

.form-section:last-child {
  margin-bottom: 0;
}

.form-section h4 {
  margin: 0 0 12px 0;
  color: #303133;
  font-size: 16px;
}

.room-capacity {
  color: #909399;
  font-size: 12px;
  margin-left: 8px;
}

.time-selection {
  display: flex;
  gap: 20px;
  margin-bottom: 16px;
}

.time-item {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.time-item label {
  font-weight: 500;
  color: #303133;
  font-size: 14px;
}

.duration-info {
  padding: 12px;
  background: #e1f3d8;
  border-radius: 8px;
  text-align: center;
}

.finished-message {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
}

.finished-message h3 {
  margin: 0;
  color: #529b2e;
}

.finished-message p {
  margin: 0;
  color: #606266;
}
</style>

Work Schedule Management

Create a work schedule management component:

vue
<template>
  <div class="work-schedule">
    <h3>Work Schedule Management</h3>
    
    <div class="schedule-form">
      <h4>Set Work Hours</h4>
      
      <div class="weekdays-schedule">
        <div
          v-for="day in weekdays"
          :key="day.key"
          class="day-schedule"
        >
          <div class="day-header">
            <el-checkbox
              v-model="day.enabled"
              @change="handleDayToggle(day)"
            >
              {{ day.name }}
            </el-checkbox>
          </div>
          
          <div v-if="day.enabled" class="time-slots">
            <div
              v-for="(slot, index) in day.timeSlots"
              :key="index"
              class="time-slot"
            >
              <el-time-select
                v-model="slot.start"
                start="00:00"
                step="00:30"
                end="23:30"
                placeholder="Start time"
                @change="validateTimeSlot(day, slot)"
              />
              <span class="time-separator">to</span>
              <el-time-select
                v-model="slot.end"
                :start="slot.start || '00:30'"
                step="00:30"
                end="23:59"
                placeholder="End time"
                :disabled="!slot.start"
              />
              <el-button
                v-if="day.timeSlots.length > 1"
                size="small"
                type="danger"
                @click="removeTimeSlot(day, index)"
              >
                Remove
              </el-button>
            </div>
            
            <el-button
              size="small"
              type="primary"
              @click="addTimeSlot(day)"
            >
              Add Time Slot
            </el-button>
          </div>
        </div>
      </div>
      
      <div class="schedule-actions">
        <el-button type="primary" @click="saveSchedule">Save Settings</el-button>
        <el-button @click="resetSchedule">Reset</el-button>
        <el-button @click="applyTemplate">Apply Template</el-button>
      </div>
    </div>
    
    <div class="schedule-preview">
      <h4>Work Schedule Preview</h4>
      <div class="preview-content">
        <div
          v-for="day in enabledDays"
          :key="day.key"
          class="preview-day"
        >
          <div class="preview-day-name">{{ day.name }}</div>
          <div class="preview-time-slots">
            <span
              v-for="(slot, index) in day.timeSlots"
              :key="index"
              class="preview-slot"
            >
              {{ slot.start }} - {{ slot.end }}
            </span>
          </div>
        </div>
        
        <div v-if="enabledDays.length === 0" class="no-schedule">
          No work hours set yet
        </div>
      </div>
      
      <div class="schedule-stats">
        <div class="stat-item">
          <span class="stat-label">Working days:</span>
          <span class="stat-value">{{ enabledDays.length }} days/week</span>
        </div>
        <div class="stat-item">
          <span class="stat-label">Total work hours:</span>
          <span class="stat-value">{{ totalWorkHours }} hours/week</span>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'
import { ElMessage } from 'element-plus'

const weekdays = ref([
  {
    key: 'monday',
    name: 'Monday',
    enabled: true,
    timeSlots: [{ start: '09:00', end: '18:00' }]
  },
  {
    key: 'tuesday',
    name: 'Tuesday',
    enabled: true,
    timeSlots: [{ start: '09:00', end: '18:00' }]
  },
  {
    key: 'wednesday',
    name: 'Wednesday',
    enabled: true,
    timeSlots: [{ start: '09:00', end: '18:00' }]
  },
  {
    key: 'thursday',
    name: 'Thursday',
    enabled: true,
    timeSlots: [{ start: '09:00', end: '18:00' }]
  },
  {
    key: 'friday',
    name: 'Friday',
    enabled: true,
    timeSlots: [{ start: '09:00', end: '18:00' }]
  },
  {
    key: 'saturday',
    name: 'Saturday',
    enabled: false,
    timeSlots: [{ start: '', end: '' }]
  },
  {
    key: 'sunday',
    name: 'Sunday',
    enabled: false,
    timeSlots: [{ start: '', end: '' }]
  }
])

const enabledDays = computed(() => {
  return weekdays.value.filter(day => 
    day.enabled && day.timeSlots.some(slot => slot.start && slot.end)
  )
})

const totalWorkHours = computed(() => {
  let total = 0
  
  enabledDays.value.forEach(day => {
    day.timeSlots.forEach(slot => {
      if (slot.start && slot.end) {
        const [startHours, startMinutes] = slot.start.split(':').map(Number)
        const [endHours, endMinutes] = slot.end.split(':').map(Number)
        
        const startTotalMinutes = startHours * 60 + startMinutes
        const endTotalMinutes = endHours * 60 + endMinutes
        
        const duration = (endTotalMinutes - startTotalMinutes) / 60
        total += duration
      }
    })
  })
  
  return total.toFixed(1)
})

const handleDayToggle = (day) => {
  if (!day.enabled) {
    // Clear time slots when disabled
    day.timeSlots = [{ start: '', end: '' }]
  } else {
    // Set default time slot when enabled
    if (!day.timeSlots[0].start) {
      day.timeSlots[0] = { start: '09:00', end: '18:00' }
    }
  }
}

const addTimeSlot = (day) => {
  day.timeSlots.push({ start: '', end: '' })
}

const removeTimeSlot = (day, index) => {
  day.timeSlots.splice(index, 1)
}

const validateTimeSlot = (day, slot) => {
  if (slot.start && slot.end && slot.start >= slot.end) {
    ElMessage.warning('End time must be greater than start time')
    slot.end = ''
  }
}

const saveSchedule = () => {
  // Validate time slots
  let isValid = true
  
  enabledDays.value.forEach(day => {
    day.timeSlots.forEach(slot => {
      if (!slot.start || !slot.end) {
        isValid = false
      }
    })
  })
  
  if (!isValid) {
    ElMessage.warning('Please complete all time slot settings')
    return
  }
  
  ElMessage.success('Work schedule settings saved')
}

const resetSchedule = () => {
  weekdays.value.forEach(day => {
    if (['monday', 'tuesday', 'wednesday', 'thursday', 'friday'].includes(day.key)) {
      day.enabled = true
      day.timeSlots = [{ start: '09:00', end: '18:00' }]
    } else {
      day.enabled = false
      day.timeSlots = [{ start: '', end: '' }]
    }
  })
  
  ElMessage.success('Reset to default work schedule')
}

const applyTemplate = () => {
  // Apply flexible work schedule template
  weekdays.value.forEach(day => {
    if (['monday', 'tuesday', 'wednesday', 'thursday', 'friday'].includes(day.key)) {
      day.enabled = true
      day.timeSlots = [
        { start: '09:00', end: '12:00' },
        { start: '13:30', end: '18:30' }
      ]
    } else {
      day.enabled = false
      day.timeSlots = [{ start: '', end: '' }]
    }
  })
  
  ElMessage.success('Applied flexible work schedule template')
}
</script>

<style scoped>
.work-schedule {
  max-width: 800px;
  padding: 20px;
}

.schedule-form {
  background: #f5f7fa;
  padding: 20px;
  border-radius: 8px;
  margin-bottom: 24px;
}

.schedule-form h4 {
  margin: 0 0 20px 0;
  color: #303133;
}

.weekdays-schedule {
  margin-bottom: 24px;
}

.day-schedule {
  margin-bottom: 20px;
  padding: 16px;
  background: white;
  border-radius: 6px;
  border: 1px solid #e4e7ed;
}

.day-header {
  margin-bottom: 12px;
}

.time-slots {
  margin-left: 24px;
}

.time-slot {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
}

.time-separator {
  color: #606266;
  font-weight: 500;
}

.schedule-actions {
  display: flex;
  gap: 12px;
}

.schedule-preview {
  background: white;
  padding: 20px;
  border-radius: 8px;
  border: 1px solid #e4e7ed;
}

.schedule-preview h4 {
  margin: 0 0 16px 0;
  color: #303133;
}

.preview-content {
  margin-bottom: 20px;
}

.preview-day {
  display: flex;
  align-items: center;
  margin-bottom: 12px;
  padding: 8px 0;
  border-bottom: 1px solid #f0f2f5;
}

.preview-day-name {
  width: 80px;
  font-weight: 500;
  color: #303133;
}

.preview-time-slots {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}

.preview-slot {
  background: #e1f3d8;
  color: #529b2e;
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 12px;
}

.no-schedule {
  text-align: center;
  color: #909399;
  padding: 40px;
  background: #f5f7fa;
  border-radius: 6px;
}

.schedule-stats {
  display: flex;
  gap: 24px;
  padding: 16px;
  background: #f8f9fa;
  border-radius: 6px;
}

.stat-item {
  display: flex;
  align-items: center;
  gap: 8px;
}

.stat-label {
  color: #606266;
  font-size: 14px;
}

.stat-value {
  color: #303133;
  font-weight: 500;
}
</style>

API Documentation

TimePicker Attributes

NameDescriptionTypeDefault
model-value / v-modelbinding valueDate / string
readonlywhether TimePicker is read onlybooleanfalse
disabledwhether TimePicker is disabledbooleanfalse
editablewhether the input is editablebooleantrue
clearablewhether to show clear buttonbooleantrue
sizesize of Inputstring
placeholderplaceholder in non-range modestring
start-placeholderplaceholder for the start time in range modestring
end-placeholderplaceholder for the end time in range modestring
is-rangewhether to pick a time rangebooleanfalse
arrow-controlwhether to pick time using arrow buttonsbooleanfalse
alignalignmentleft / center / rightleft
popper-classcustom class name for TimePicker's dropdownstring
range-separatorrange separatorstring'-'
formatformat of the displayed value in the input boxstringHH:mm:ss
value-formatbinding value formatstring
default-valueoptional, default date of the calendarDate / string
namenative attributestring
prefix-iconcustom prefix iconstring / ComponentClock
clear-iconcustom clear iconstring / ComponentCircleClose
disabled-hoursa function that disables specific hoursFunction
disabled-minutesa function that disables specific minutesFunction
disabled-secondsa function that disables specific secondsFunction
teleportedwhether TimePicker dropdown is teleported to the bodybooleantrue

TimeSelect Attributes

NameDescriptionTypeDefault
model-value / v-modelbinding valuestring
disabledwhether TimeSelect is disabledbooleanfalse
editablewhether the input is editablebooleantrue
clearablewhether to show clear buttonbooleantrue
sizesize of Inputstring
placeholderplaceholderstring
namenative attributestring
effectTooltip themestringlight
prefix-iconcustom prefix iconstring / ComponentClock
clear-iconcustom clear iconstring / ComponentCircleClose
startstart timestring09:00
endend timestring18:00
steptime stepstring00:30
min-timeminimum timestring00:00
max-timemaximum timestring
formatformat of the displayed value in the input boxstringHH:mm

TimePicker Events

NameDescriptionParameters
changetriggers when user confirms the valuecomponent's binding value
blurtriggers when Input blurscomponent instance
focustriggers when Input focusescomponent instance
visible-changetriggers when the TimePicker's dropdown appears/disappearstrue when it appears, and false otherwise

TimePicker Methods

MethodDescriptionParameters
focusfocus the Input component
blurblur the Input component

Practice Exercises

Exercise 1: Class Schedule Time Setting

Create a class schedule time setting system:

vue
<template>
  <div class="course-schedule">
    <h3>Class Schedule Setting</h3>
    
    <div class="schedule-settings">
      <h4>Set Class Times</h4>
      
      <div class="time-periods">
        <div
          v-for="(period, index) in timePeriods"
          :key="index"
          class="period-item"
        >
          <div class="period-label">Class {{ index + 1 }}</div>
          <el-time-select
            v-model="period.start"
            start="08:00"
            step="00:05"
            end="22:00"
            placeholder="Start time"
          />
          <span class="time-separator">-</span>
          <el-time-select
            v-model="period.end"
            :start="period.start || '08:05'"
            step="00:05"
            end="22:00"
            placeholder="End time"
            :disabled="!period.start"
          />
          <el-button
            v-if="timePeriods.length > 1"
            size="small"
            type="danger"
            @click="removePeriod(index)"
          >
            Delete
          </el-button>
        </div>
      </div>
      
      <div class="period-actions">
        <el-button size="small" @click="addPeriod">Add Class Period</el-button>
        <el-button size="small" @click="applyStandardSchedule">Apply Standard Schedule</el-button>
      </div>
    </div>
    
    <div class="schedule-preview">
      <h4>Schedule Preview</h4>
      <div class="preview-table">
        <div class="time-column">
          <div class="time-header">Time</div>
          <div
            v-for="(period, index) in validPeriods"
            :key="index"
            class="time-cell"
          >
            {{ period.start }} - {{ period.end }}
          </div>
        </div>
        
        <div
          v-for="day in weekDays"
          :key="day"
          class="day-column"
        >
          <div class="day-header">{{ day }}</div>
          <div
            v-for="(period, index) in validPeriods"
            :key="index"
            class="course-cell"
          >
            <!-- Course content can be added here -->
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'
import { ElMessage } from 'element-plus'

const timePeriods = ref([
  { start: '08:00', end: '08:45' },
  { start: '08:55', end: '09:40' },
  { start: '10:00', end: '10:45' },
  { start: '10:55', end: '11:40' },
  { start: '14:00', end: '14:45' },
  { start: '14:55', end: '15:40' },
  { start: '16:00', end: '16:45' },
  { start: '16:55', end: '17:40' }
])

const weekDays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']

const validPeriods = computed(() => {
  return timePeriods.value.filter(period => period.start && period.end)
})

const addPeriod = () => {
  timePeriods.value.push({ start: '', end: '' })
}

const removePeriod = (index) => {
  timePeriods.value.splice(index, 1)
}

const applyStandardSchedule = () => {
  timePeriods.value = [
    { start: '08:00', end: '08:45' },
    { start: '08:55', end: '09:40' },
    { start: '10:00', end: '10:45' },
    { start: '10:55', end: '11:40' },
    { start: '14:00', end: '14:45' },
    { start: '14:55', end: '15:40' },
    { start: '16:00', end: '16:45' },
    { start: '16:55', end: '17:40' }
  ]
  
  ElMessage.success('Standard class schedule applied')
}
</script>

<style scoped>
.course-schedule {
  max-width: 1000px;
  padding: 20px;
}

.schedule-settings {
  background: #f5f7fa;
  padding: 20px;
  border-radius: 8px;
  margin-bottom: 24px;
}

.schedule-settings h4 {
  margin: 0 0 16px 0;
  color: #303133;
}

.time-periods {
  margin-bottom: 16px;
}

.period-item {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
  padding: 12px;
  background: white;
  border-radius: 6px;
  border: 1px solid #e4e7ed;
}

.period-label {
  width: 80px;
  font-weight: 500;
  color: #303133;
}

.time-separator {
  color: #606266;
}

.period-actions {
  display: flex;
  gap: 12px;
}

.schedule-preview {
  background: white;
  padding: 20px;
  border-radius: 8px;
  border: 1px solid #e4e7ed;
}

.schedule-preview h4 {
  margin: 0 0 16px 0;
  color: #303133;
}

.preview-table {
  display: flex;
  border: 1px solid #e4e7ed;
  border-radius: 6px;
  overflow: hidden;
}

.time-column,
.day-column {
  flex: 1;
  border-right: 1px solid #e4e7ed;
}

.day-column:last-child {
  border-right: none;
}

.time-header,
.day-header {
  padding: 12px 8px;
  background: #f5f7fa;
  font-weight: 500;
  text-align: center;
  border-bottom: 1px solid #e4e7ed;
}

.time-cell,
.course-cell {
  padding: 8px;
  min-height: 40px;
  border-bottom: 1px solid #f0f2f5;
  font-size: 12px;
  text-align: center;
}

.time-cell {
  background: #fafafa;
  color: #606266;
}

.course-cell {
  background: white;
}
</style>

Exercise 2: Countdown Timer Setting

Create a countdown timer setting component:

vue
<template>
  <div class="countdown-timer">
    <h3>Countdown Timer</h3>
    
    <div class="timer-settings">
      <h4>Set Countdown Time</h4>
      
      <div class="time-input">
        <div class="input-group">
          <label>Hours:</label>
          <el-input-number
            v-model="hours"
            :min="0"
            :max="23"
            controls-position="right"
          />
        </div>
        
        <div class="input-group">
          <label>Minutes:</label>
          <el-input-number
            v-model="minutes"
            :min="0"
            :max="59"
            controls-position="right"
          />
        </div>
        
        <div class="input-group">
          <label>Seconds:</label>
          <el-input-number
            v-model="seconds"
            :min="0"
            :max="59"
            controls-position="right"
          />
        </div>
      </div>
      
      <div class="quick-settings">
        <h5>Quick Settings</h5>
        <div class="quick-buttons">
          <el-button size="small" @click="setTime(0, 1, 0)">1 minute</el-button>
          <el-button size="small" @click="setTime(0, 5, 0)">5 minutes</el-button>
          <el-button size="small" @click="setTime(0, 10, 0)">10 minutes</el-button>
          <el-button size="small" @click="setTime(0, 30, 0)">30 minutes</el-button>
          <el-button size="small" @click="setTime(1, 0, 0)">1 hour</el-button>
        </div>
      </div>
      
      <div class="timer-controls">
        <el-button
          type="primary"
          :disabled="totalSeconds === 0"
          @click="startTimer"
        >
          Start Countdown
        </el-button>
        <el-button @click="resetTimer">Reset</el-button>
      </div>
    </div>
    
    <div v-if="isRunning || remainingTime > 0" class="timer-display">
      <div class="countdown-circle">
        <div class="time-display">
          {{ formatTime(remainingTime) }}
        </div>
        <div class="progress-ring">
          <svg width="200" height="200">
            <circle
              cx="100"
              cy="100"
              r="90"
              fill="none"
              stroke="#e4e7ed"
              stroke-width="8"
            />
            <circle
              cx="100"
              cy="100"
              r="90"
              fill="none"
              stroke="#409EFF"
              stroke-width="8"
              stroke-linecap="round"
              :stroke-dasharray="circumference"
              :stroke-dashoffset="strokeDashoffset"
              transform="rotate(-90 100 100)"
            />
          </svg>
        </div>
      </div>
      
      <div class="timer-controls">
        <el-button
          v-if="!isRunning"
          type="primary"
          @click="startTimer"
        >
          Continue
        </el-button>
        <el-button
          v-if="isRunning"
          type="warning"
          @click="pauseTimer"
        >
          Pause
        </el-button>
        <el-button @click="stopTimer">Stop</el-button>
      </div>
    </div>
    
    <div v-if="isFinished" class="timer-finished">
      <div class="finished-message">
        <el-icon size="48" color="#67c23a">
          <Check />
        </el-icon>
        <h3>Countdown Complete!</h3>
        <p>The set time has elapsed</p>
      </div>
      
      <el-button type="primary" @click="resetTimer">
        Set New Timer
      </el-button>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, onUnmounted } from 'vue'
import { Check } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'

const hours = ref(0)
const minutes = ref(5)
const seconds = ref(0)
const remainingTime = ref(0)
const isRunning = ref(false)
const isFinished = ref(false)
const timer = ref(null)

const totalSeconds = computed(() => {
  return hours.value * 3600 + minutes.value * 60 + seconds.value
})

const circumference = computed(() => {
  return 2 * Math.PI * 90 // r = 90
})

const strokeDashoffset = computed(() => {
  if (totalSeconds.value === 0) return circumference.value
  const progress = remainingTime.value / totalSeconds.value
  return circumference.value * (1 - progress)
})

const setTime = (h, m, s) => {
  hours.value = h
  minutes.value = m
  seconds.value = s
}

const startTimer = () => {
  if (remainingTime.value === 0) {
    remainingTime.value = totalSeconds.value
  }
  
  if (remainingTime.value === 0) {
    ElMessage.warning('Please set a countdown time')
    return
  }
  
  isRunning.value = true
  isFinished.value = false
  
  timer.value = setInterval(() => {
    remainingTime.value--
    
    if (remainingTime.value <= 0) {
      clearInterval(timer.value)
      isRunning.value = false
      isFinished.value = true
      remainingTime.value = 0
      
      // Play sound or show notification
      ElMessage.success('Countdown complete!')
    }
  }, 1000)
}

const pauseTimer = () => {
  if (timer.value) {
    clearInterval(timer.value)
    timer.value = null
  }
  isRunning.value = false
}

const stopTimer = () => {
  if (timer.value) {
    clearInterval(timer.value)
    timer.value = null
  }
  isRunning.value = false
  remainingTime.value = 0
  isFinished.value = false
}

const resetTimer = () => {
  stopTimer()
  hours.value = 0
  minutes.value = 5
  seconds.value = 0
}

const formatTime = (totalSeconds) => {
  const h = Math.floor(totalSeconds / 3600)
  const m = Math.floor((totalSeconds % 3600) / 60)
  const s = totalSeconds % 60
  
  if (h > 0) {
    return `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`
  } else {
    return `${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`
  }
}

onUnmounted(() => {
  if (timer.value) {
    clearInterval(timer.value)
  }
})
</script>

<style scoped>
.countdown-timer {
  max-width: 600px;
  padding: 20px;
  margin: 0 auto;
}

.timer-settings {
  background: #f5f7fa;
  padding: 20px;
  border-radius: 8px;
  margin-bottom: 24px;
}

.timer-settings h4 {
  margin: 0 0 16px 0;
  color: #303133;
}

.time-input {
  display: flex;
  gap: 20px;
  margin-bottom: 20px;
  justify-content: center;
}

.input-group {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}

.input-group label {
  font-weight: 500;
  color: #303133;
}

.quick-settings {
  margin-bottom: 20px;
}

.quick-settings h5 {
  margin: 0 0 12px 0;
  color: #303133;
  text-align: center;
}

.quick-buttons {
  display: flex;
  gap: 8px;
  justify-content: center;
  flex-wrap: wrap;
}

.timer-controls {
  display: flex;
  gap: 12px;
  justify-content: center;
}

.timer-display {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  padding: 40px;
  background: white;
  border-radius: 8px;
  border: 1px solid #e4e7ed;
  margin-bottom: 24px;
}

.countdown-circle {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}

.time-display {
  position: absolute;
  font-size: 24px;
  font-weight: bold;
  color: #303133;
  text-align: center;
}

.progress-ring {
  transform: rotate(-90deg);
}

.timer-finished {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  padding: 40px;
  background: white;
  border-radius: 8px;
  border: 1px solid #e4e7ed;
}

.finished-message {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
}

.finished-message h3 {
  margin: 0;
  color: #67c23a;
}

.finished-message p {
  margin: 0;
  color: #606266;
}
</style>

Element Plus Study Guide