Using Preline UI with Svelte
A practical guide to using Preline UI JavaScript plugins in Svelte and SvelteKit projects, including onMount, tick, afterNavigate, actions, cleanup, and optional dependencies.
View guideUpdate v4.2 - New components, 10+ framework guides, and quality improvements. Visit Changelog
A practical guide to wiring Preline UI into SolidJS without fighting Solid's rendering model, refs, and router updates.
SolidJS and Preline UI fit together best when Solid owns rendering and Preline UI attaches behavior after the DOM is already in place. The important part is not a special Solid adapter. It is choosing the right Preline UI entry and putting initialization in Solid's lifecycle.
The current Preline UI package exposes preline/non-auto, named plugin classes, and single-plugin packages, so Solid can render first and initialize only the DOM nodes that are already committed.
Preline UI is a DOM-driven Tailwind CSS component system. Solid renders JSX to real DOM nodes; Preline UI scans those nodes and attaches behavior to matching markup. That is the same contract Preline UI uses in plain HTML, Astro, Vue, Svelte, Angular, React, Laravel, Rails, and similar stacks.
The tradeoff is explicit lifecycle work. Initialize after Solid has mounted the markup, rescan after route content changes, and destroy manually created instances when Solid removes their root element.
Use onMount for browser-only initialization. Pair it with onCleanup when the component owns a group of initialized Preline UI markup.
import { onCleanup, onMount } from "solid-js";
import { HSStaticMethods } from "preline/non-auto";
export default function DropdownSection() {
onMount(() => {
HSStaticMethods.autoInit(["dropdown"]);
});
onCleanup(() => {
HSStaticMethods.cleanCollection("dropdown");
});
return (
<div class="hs-dropdown relative inline-flex">
<button class="hs-dropdown-toggle" type="button">
Toggle
</button>
<div class="hs-dropdown-menu hidden">Menu</div>
</div>
);
}
This keeps Preline UI out of server rendering and avoids relying on browser script or plugin auto-entry page-load timing.
Client-side navigation can replace route markup without a page reload. Put the rescan in a component that is rendered inside the router context, read location.pathname inside createEffect, then defer autoInit to the next microtask so Solid has committed the route DOM.
import { createEffect } from "solid-js";
import { useLocation } from "@solidjs/router";
import { HSStaticMethods } from "preline/non-auto";
export function PrelineRouterSync() {
const location = useLocation();
createEffect(() => {
location.pathname;
queueMicrotask(() => {
HSStaticMethods.autoInit();
});
});
return null;
}
In @solidjs/router, useLocation() must run inside a route context. Place this helper in a route layout or another component rendered under <Route>, not as a loose child outside routing.
For a full Preline UI installation, preline/non-auto is the most practical Solid default. It gives you HSStaticMethods and plugin classes without automatic initialization on page load.
import { HSStaticMethods } from "preline/non-auto";
HSStaticMethods.autoInit(["dropdown", "overlay"]);
HSStaticMethods.cleanCollection(["dropdown", "overlay"]);
If a surface only needs one class from the full package, import that class from preline/non-auto. This keeps strict TypeScript builds on the declared package surface.
import { HSDropdown } from "preline/non-auto";
HSDropdown.autoInit();
Preline UI plugins can also be consumed from single-plugin dependencies when those packages are available in your dependency set, for example @preline/dropdown, @preline/overlay, @preline/select, or @preline/range-slider. This is useful when a Solid component only needs one or two interactive primitives.
npm install @preline/dropdown
import { onMount } from "solid-js";
import HSDropdown from "@preline/dropdown/non-auto";
export default function Dropdown() {
onMount(() => {
HSDropdown.autoInit();
});
return (
<div class="hs-dropdown relative inline-flex">
...
</div>
);
}
In that single-package setup, the auto entry is import "@preline/dropdown". It is useful for simple static pages. In routed Solid apps, /non-auto keeps initialization tied to Solid lifecycle timing.
autoInit is convenient for page-level scans. A manual instance is better when one Solid component owns one plugin root and can destroy it locally.
import { onCleanup, onMount } from "solid-js";
import { HSDropdown, type IHTMLElementFloatingUI } from "preline/non-auto";
export default function Dropdown() {
let dropdownRoot!: HTMLDivElement;
let dropdown: InstanceType<typeof HSDropdown> | undefined;
onMount(() => {
dropdown = new HSDropdown(dropdownRoot as unknown as IHTMLElementFloatingUI);
});
onCleanup(() => {
dropdown?.destroy();
});
return (
<div ref={dropdownRoot} class="hs-dropdown relative inline-flex">
<button class="hs-dropdown-toggle" type="button">
Toggle
</button>
<div class="hs-dropdown-menu hidden">Menu</div>
</div>
);
}
Preline UI stores plugin instances in internal collections such as window.$hsDropdownCollection. That registry lets plugins coordinate across plain HTML and framework environments without requiring framework context.
In Solid, the practical rule is straightforward: call destroy() for manual instances, and call cleanCollection() when a component or route intentionally removes a group of initialized markup.
HSStaticMethods.cleanCollection("dropdown");
HSStaticMethods.cleanCollection(["dropdown", "overlay"]);
Most core plugins do not use jQuery. Dropdowns, overlays, tooltips, popovers, tabs, and similar components use plain JavaScript. Positioning behavior uses @floating-ui/dom.
jQuery is only relevant for Datatable because datatables.net depends on it. If jQuery and DataTables are not present, Datatable should not initialize. That dependency does not affect dropdowns, overlays, tabs, or tooltips.
Range Slider uses the JavaScript API from noUiSlider. Preline UI remains responsible for the Tailwind CSS markup and behavior wrapper; noUiSlider CSS classes do not need to be merged into Preline UI styling.
preline/non-auto in Solid when you need explicit lifecycle control.HSStaticMethods.autoInit() in onMount after the target markup exists.createEffect plus queueMicrotask for route rescans under @solidjs/router.destroy() for reusable components that own one plugin root.cleanCollection() when removing initialized groups of markup.datatables.net for Datatable or noUiSlider for Range Slider.A practical guide to using Preline UI JavaScript plugins in Svelte and SvelteKit projects, including onMount, tick, afterNavigate, actions, cleanup, and optional dependencies.
View guideA practical guide to using Preline UI JavaScript plugins in Qwik projects, including visible tasks, Qwik City navigation, module imports, cleanup, and optional dependencies.
View guide