When Should We Come?

A booking without a date is useless. Customers need to pick when they want their service. HTML’s native date input works well for this, and Svelte’s binding makes it easy to work with.


What You’ll Learn

  • Bind to date input values
  • Set minimum and maximum dates
  • Format dates for display
  • Handle date validation

The Basic Date Input

Date inputs bind just like text inputs:

<script>
  let bookingDate = $state('');
</script>

<label for="booking-date">Preferred Date</label>
<input 
  type="date" 
  id="booking-date"
  bind:value={bookingDate}
/>

<p>Selected: {bookingDate || 'No date selected'}</p>

The value is a string in YYYY-MM-DD format (e.g., “2025-06-15”).


Prevent Past Dates

Customers can’t book services for yesterday. Set a minimum date:

<script>
  let bookingDate = $state('');
  
  // Get today's date in YYYY-MM-DD format
  function getTodayString() {
    return new Date().toISOString().split('T')[0];
  }
  
  let minDate = getTodayString();
</script>

<label for="booking-date">Preferred Date</label>
<input 
  type="date" 
  id="booking-date"
  bind:value={bookingDate}
  min={minDate}
  required
/>

The browser now greys out past dates in the picker.


Limit How Far Ahead

Maybe you only book 3 months in advance:

<script>
  let bookingDate = $state('');
  
  function getDateString(date) {
    return date.toISOString().split('T')[0];
  }
  
  let today = new Date();
  let minDate = getDateString(today);
  
  // 3 months from now
  let maxDate = getDateString(
    new Date(today.getFullYear(), today.getMonth() + 3, today.getDate())
  );
</script>

<label for="booking-date">Preferred Date</label>
<input 
  type="date" 
  id="booking-date"
  bind:value={bookingDate}
  min={minDate}
  max={maxDate}
  required
/>

<p class="hint">Book up to 3 months in advance</p>

Format for Display

The raw YYYY-MM-DD format isn’t user-friendly. Format it nicely:

<script>
  let bookingDate = $state('');
  
  function formatDate(dateString) {
    if (!dateString) return '';
    
    const date = new Date(dateString + 'T00:00:00');
    return date.toLocaleDateString('en-US', {
      weekday: 'long',
      year: 'numeric',
      month: 'long',
      day: 'numeric'
    });
  }
  
  let formattedDate = $derived(formatDate(bookingDate));
</script>

<label for="booking-date">Preferred Date</label>
<input 
  type="date" 
  id="booking-date"
  bind:value={bookingDate}
  required
/>

{#if bookingDate}
  <p class="selected-date">{formattedDate}</p>
{/if}

Now “2025-06-15” displays as “Sunday, June 15, 2025”.

Note: We add T00:00:00 to avoid timezone issues when parsing the date string.


Add to the Booking Form

Integrate the date picker with the contact fields:

<!-- filename: src/lib/components/BookingForm.svelte -->
<script>
  // Contact fields
  let customerName = $state('');
  let customerEmail = $state('');
  
  // Date selection
  let bookingDate = $state('');
  
  function getDateString(date) {
    return date.toISOString().split('T')[0];
  }
  
  let today = new Date();
  let minDate = getDateString(today);
  let maxDate = getDateString(
    new Date(today.getFullYear(), today.getMonth() + 3, today.getDate())
  );
  
  function formatDate(dateString) {
    if (!dateString) return '';
    const date = new Date(dateString + 'T00:00:00');
    return date.toLocaleDateString('en-US', {
      weekday: 'long',
      month: 'long',
      day: 'numeric'
    });
  }
</script>

<form>
  <fieldset>
    <legend>Contact Information</legend>
    <!-- Name and email fields... -->
  </fieldset>
  
  <fieldset>
    <legend>Appointment Details</legend>
    
    <div class="field">
      <label for="booking-date">Preferred Date</label>
      <input 
        type="date" 
        id="booking-date"
        name="bookingDate"
        bind:value={bookingDate}
        min={minDate}
        max={maxDate}
        required
      />
      {#if bookingDate}
        <p class="date-preview">{formatDate(bookingDate)}</p>
      {/if}
    </div>
  </fieldset>
</form>

<style>
  .date-preview {
    margin: 0.25rem 0 0 0;
    color: #007bff;
    font-size: 0.875rem;
  }
</style>

Check Day of Week

Maybe you don’t work weekends:

<script>
  let bookingDate = $state('');
  
  let isWeekend = $derived(() => {
    if (!bookingDate) return false;
    const date = new Date(bookingDate + 'T00:00:00');
    const day = date.getDay();
    return day === 0 || day === 6; // Sunday or Saturday
  });
</script>

<input type="date" bind:value={bookingDate} />

{#if isWeekend()}
  <p class="warning">
    ⚠️ We don't offer services on weekends. Please select a weekday.
  </p>
{/if}

This provides immediate feedback, though server-side validation will ultimately enforce the rule.


Default to Tomorrow

Pre-select a sensible default:

<script>
  function getDateString(date) {
    return date.toISOString().split('T')[0];
  }
  
  function getTomorrow() {
    const tomorrow = new Date();
    tomorrow.setDate(tomorrow.getDate() + 1);
    return getDateString(tomorrow);
  }
  
  let bookingDate = $state(getTomorrow());
</script>

The form starts with tomorrow selected, saving customers a click.


Common Mistakes

Timezone Parsing Issues

<script>
  let dateString = '2025-06-15';
  
  // ❌ May give wrong day due to timezone
  const date = new Date(dateString);
  
  // ✅ Explicit time prevents timezone shift
  const date = new Date(dateString + 'T00:00:00');
</script>

Forgetting min Attribute

<!-- ❌ Users can select past dates -->
<input type="date" bind:value={bookingDate} />

<!-- ✅ Prevent past dates -->
<input type="date" bind:value={bookingDate} min={today} />

Always set min to prevent invalid selections.


Summary

Date inputs work seamlessly with Svelte’s binding. Use min and max to constrain valid ranges, and format dates nicely for display. The native date picker handles most complexity.

Key takeaways:

  • bind:value works with type="date"
  • Values are strings in YYYY-MM-DD format
  • Use min and max to constrain date ranges
  • Format with toLocaleDateString() for display

Next Steps

Customers pick a date, but what time? Continue with Time Selection Dropdown to add time slot selection.