Интеграция Flatpickr в Svelte строится вокруг идеи: DOM-ориентированная библиотека управляет конкретным input-элементом, а Svelte отвечает за реактивность и жизненный цикл компонента. Основная сложность заключается не в инициализации, а в корректном разрушении экземпляра и синхронизации состояния.
Flatpickr работает напрямую с DOM, поэтому в Svelte его подключение
всегда выполняется внутри onMount, когда элемент уже
существует в DOM-дереве.
<script>
import { onMount } from "svelte";
import flatpickr from "flatpickr";
let input;
let picker;
onMount(() => {
picker = flatpickr(input, {
dateFormat: "Y-m-d",
});
return () => {
picker.destroy();
};
});
</script>
<input bind:this={input} type="text" />
Ключевой момент: bind:this передаёт ссылку на реальный
DOM-элемент, который Flatpickr использует как точку привязки.
В Svelte состояние обычно хранится в переменных. Flatpickr не знает о реактивности, поэтому требуется вручную синхронизировать значение.
<script>
import { onMount } from "svelte";
import flatpickr from "flatpickr";
let input;
let picker;
let date = "";
onMount(() => {
picker = flatpickr(input, {
dateFormat: "Y-m-d",
defaultDate: date,
onChange: (selectedDates, dateStr) => {
date = dateStr;
}
});
return () => picker.destroy();
});
</script>
<input bind:this={input} bind:value={date} />
<p>Выбранная дата: {date}</p>
Здесь происходит двусторонняя логика:
date через
onChangebind:valueРеактивность Svelte позволяет менять дату без взаимодействия с календарём, но Flatpickr нужно уведомлять вручную.
<script>
import { onMount } from "svelte";
import flatpickr from "flatpickr";
let input;
let picker;
let date = "2026-01-01";
onMount(() => {
picker = flatpickr(input, {
defaultDate: date,
onChange: (_, d) => date = d
});
return () => picker.destroy();
});
$: if (picker && date) {
picker.setDate(date, true);
}
</script>
<input bind:this={input} bind:value={date} />
Конструкция $: обеспечивает синхронизацию при изменении
date.
Наиболее чистый способ интеграции — использование actions. Это позволяет инкапсулировать логику и не засорять компонент.
// flatpickrAction.js
import flatpickr from "flatpickr";
export function flatpickrAction(node, options = {}) {
const instance = flatpickr(node, options);
return {
upd ate(newOptions) {
instance.se t(options = newOptions);
},
destroy() {
instance.destroy();
}
};
}
Использование:
<script>
import { flatpickrAction } from "./flatpickrAction";
let date;
</script>
<input use:flatpickrAction={{ dateFormat: "Y-m-d" }} bind:value={date} />
Action-подход делает Flatpickr частью декларативного Svelte-кода, минимизируя ручное управление жизненным циклом.
В более сложных приложениях состояние часто выносится в store.
// dateStore.js
import { writable } from "svelte/store";
export const dateStore = writable("");
<script>
import { onMount } from "svelte";
import flatpickr from "flatpickr";
import { dateStore } from "./dateStore";
let input;
let picker;
let unsubscribe;
onMount(() => {
unsubscribe = dateStore.subscribe(value => {
if (picker) picker.setDate(value, false);
});
picker = flatpickr(input, {
onChange: (_, d) => dateStore.set(d)
});
return () => {
unsubscribe();
picker.destroy();
};
});
</script>
<input bind:this={input} />
Store выступает единым источником истины, а Flatpickr становится лишь интерфейсом ввода.
Flatpickr поддерживает range mode, что важно для интерфейсов бронирования и фильтрации.
<script>
import { onMount } from "svelte";
import flatpickr from "flatpickr";
let input;
let picker;
let range = [];
onMount(() => {
picker = flatpickr(input, {
mode: "range",
onChange: (selectedDates) => {
range = selectedDates;
}
});
return () => picker.destroy();
});
</script>
<input bind:this={input} />
Особенность Svelte: массив range обновляется реактивно,
что позволяет легко привязывать его к UI-фильтрам.
При работе в Svelte + TypeScript важно типизировать экземпляр Flatpickr.
<script lang="ts">
import { onMount } from "svelte";
import flatpickr, { Instance } from "flatpickr";
let input: HTMLInputElement;
let picker: Instance | null = null;
onMount(() => {
picker = flatpickr(input, {
dateFormat: "Y-m-d"
});
return () => picker?.destroy();
});
</script>
Тип Instance предотвращает ошибки при вызове методов
setDate, clear, destroy.
При использовании SvelteKit важно учитывать, что серверный рендеринг
не имеет доступа к window и DOM.
Flatpickr должен загружаться только на клиенте:
<script>
import { onMount } from "svelte";
let input;
onMount(async () => {
const flatpickr = (await import("flatpickr")).default;
flatpickr(input, {
dateFormat: "Y-m-d"
});
});
</script>
<input bind:this={input} />
Динамический import гарантирует отсутствие ошибок SSR.
Flatpickr предоставляет CSS-базу, которую можно переопределять.
import "flatpickr/dist/flatpickr.css";
import "flatpickr/dist/themes/dark.css";
В Svelte стили часто переопределяются локально:
<style>
:global(.flatpickr-calendar) {
border-radius: 12px;
}
:global(.flatpickr-day.selected) {
background: #4f46e5;
}
</style>
В Svelte можно легко создавать несколько независимых календарей.
<script>
import { onMount } from "svelte";
import flatpickr from "flatpickr";
let inputs = [];
let pickers = [];
onMount(() => {
pickers = inputs.map(input =>
flatpickr(input, { dateFormat: "Y-m-d" })
);
return () => pickers.forEach(p => p.destroy());
});
</script>
<input bind:this={el => inputs[0] = el} />
<input bind:this={el => inputs[1] = el} />
В реактивных компонентах Svelte важно избегать повторного создания Flatpickr при каждом обновлении состояния.
Правильный подход:
onMountsetDate, setdestroyНеправильный подход:
$: реактивных блоковFlatpickr можно комбинировать с компонентной архитектурой Svelte.
<!-- DateInput.svelte -->
<script>
export let value = "";
export let input;
</script>
<input bind:this={input} bind:value />
<script>
import DateInput from "./DateInput.svelte";
import flatpickr from "flatpickr";
import { onMount } from "svelte";
let input;
let date;
onMount(() => {
flatpickr(input, {
onChange: (_, d) => date = d
});
});
</script>
<DateInput bind:input />
При использовании Svelte форм важно помнить, что Flatpickr не
интегрирован с нативной системой bind:group или
form автоматически. Все изменения должны синхронизироваться
вручную через события.
Рекомендуемая схема:
setDateFlatpickr создаёт DOM-структуру календаря вне Svelte tree. Это означает:
Оптимальная стратегия — один экземпляр на input и управление через API, а не пересоздание.