Skip to content

Instantly share code, notes, and snippets.

@code3z
Last active June 2, 2022 01:47
Show Gist options
  • Save code3z/906679aa52c1554df37501698651604d to your computer and use it in GitHub Desktop.
Save code3z/906679aa52c1554df37501698651604d to your computer and use it in GitHub Desktop.
Simple Time Picker in Svelte

Here's a simple date & time picker in svelte using tailwind and typescript, I made it to schedule reminders in my app. It uses the 12-hour AM/PM clock. You'll need to change the tailwind bg- and color- classes to match with your app.

Check the source code, it emits the 'set' event when a time is set. It accepts optional property "time," which is mmilliseconds since the epoch or any other value that can be used to make a Date.

Features:

🎨 Styled in tailwind

⌨️ Typed in typescript - no any!

⏰ Uses the current time as the default, or accepts a custom time

⏰ User-friendly and obvious AM/PM switch

🔧 Forces correct formatting, with single-digit minutes starting with 0

🔧 Forces valid times

🚀 ~100 lines of code

screenshot

<script lang="ts">
export let primary = false;
export let danger = false;
export let fullWidth = false;
export let href = '';
let className = '';
export { className as class };
const primaryStyle = 'bg-brand-blue hover:bg-brand-blue text-white';
const secondaryStyle = 'text-brand-blue hover:bg-background-darker';
const dangerStyle = 'bg-red !border-red text-white';
const props = {
class: `hover:opacity-80 my-2 mr-4 p-2 px-5 border-2 rounded-xl border-brand-blue no-link-style
${primary ? primaryStyle : ''}
${!primary && !danger ? secondaryStyle : ''}
${danger ? dangerStyle : ''}
${fullWidth ? 'w-full' : ''}
${className} `
};
</script>
{#if href !== ''}
<a {href} {...props}><slot /></a>
{:else}
<button on:click {...props}><slot /></button>
{/if}
<script lang="ts">
export let time: number;
import Button from './Button.svelte';
const now = time ? new Date(time) : new Date();
// find tomorrow:
let date = `${now.getFullYear()}-${(now.getMonth() + 1).toString().padStart(2, '0')}-${(
now.getDate() + 1
)
.toString()
.padStart(2, '0')}`;
let minutesCount = now.getMinutes();
let isPM;
let hour = now.getHours();
let formattedMinutesCount;
$: formattedMinutesCount =
minutesCount < 10 ? minutesCount.toString().padStart(2, '0') : minutesCount;
const onMinuteInput = (e) => {
let count = Number((e.target as HTMLInputElement).value);
if (count > 60) {
minutesCount = 60;
} else {
minutesCount = count;
}
};
const fixMinuteInput = (e) => (e.target.value = formattedMinutesCount);
function setReminder() {
let fixedHour = hour === 12 ? 0 : hour;
const timeString = `${date} ${isPM ? fixedHour + 12 : fixedHour}:${formattedMinutesCount} `;
const time = new Date(timeString.trim()).getTime();
dispatch('set', { time });
}
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
</script>
<h3>Pick TIme</h3>
<label class="text-left" for="date">Date</label>
<input id="date" bind:value={date} class="color-inherit my-2 mx-auto mb-4 block rounded-xl bg-background-darker px-2.5" type="date" />
<label class="text-left" for="date">Time</label>
<p class="whitespace-nowrap">
<input
class="color-inherit appearance-textfield w-5 bg-background-darker"
min="0"
max="12"
bind:value={hour}
type="number"
/>:
<input
class="color-inherit appearance-textfield w-5 bg-background-darker"
min="0"
max="60"
on:input={onMinuteInput}
on:blur={fixMinuteInput}
value={formattedMinutesCount}
type="number"
/>
<button on:click={() => (isPM = !isPM)}>{isPM ? 'PM' : 'AM'}</button>
<br />
<button class="mx-auto block italic" on:click={() => (isPM = !isPM)}
>Switch to {isPM ? 'AM' : 'PM'}</button
>
</p>
<Button class="mx-auto mb-0 block w-full" primary={true} on:click={setReminder}>Pick Time</Button
>
<style>
.appearance-textfield {
-webkit-appearance: textfield;
-moz-appearance: textfield;
appearance: textfield;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment