Update v4.2 - New components, 10+ framework guides, and quality improvements. Visit Changelog

Svelte

Using Preline UI with Svelte

A practical guide to wiring Preline UI into Svelte without fighting Svelte rendering, actions, and SvelteKit navigation.

Svelte and Preline UI work cleanly when Svelte owns rendering and Preline UI runs after the DOM exists. The integration is mostly about timing: initialize after Svelte has flushed the markup, and destroy manually created plugin instances when Svelte removes the node.

The current Preline UI package exposes the pieces Svelte needs directly: preline/non-auto for explicit scans, named plugin classes for manual instances, and single-plugin packages for smaller surfaces.

Start with the Svelte mental model

Preline UI is a DOM-driven Tailwind CSS component system. Svelte compiles and updates the DOM; Preline UI scans that DOM and attaches behavior to matching markup. This is why the same dropdown, overlay, tabs, tooltip, or select markup can move between Svelte, React, Vue, Angular, plain HTML, Astro, Laravel, Rails, and similar stacks.

The tradeoff is explicit lifecycle work. Preline UI should run after Svelte renders, not while the component is still being created on the server or before the route content is present.

Run autoInit inside onMount after tick

Use onMount for browser-only initialization and tick to wait for Svelte's DOM flush. Keep the onMount callback synchronous if you return cleanup; Svelte does not use a cleanup function returned from an async callback.

DropdownSection.svelte
                        
                          <script lang="ts">
                            import { onMount, tick } from "svelte";
                            import { HSStaticMethods } from "preline/non-auto";

                            onMount(() => {
                              tick().then(() => {
                                HSStaticMethods.autoInit(["dropdown"]);
                              });

                              return () => {
                                HSStaticMethods.cleanCollection("dropdown");
                              };
                            });
                          </script>
                        
                      

This is the Svelte equivalent of initializing after mount in other frameworks. It also avoids running Preline UI during server rendering.

Reinitialize after SvelteKit navigation

In SvelteKit, client-side navigation can replace route markup without a full page load. Use afterNavigate, then wait for tick before scanning the new DOM.

+layout.svelte
                        
                          <script lang="ts">
                            import { afterNavigate } from "$app/navigation";
                            import { tick } from "svelte";
                            import { HSStaticMethods } from "preline/non-auto";

                            afterNavigate(() => {
                              tick().then(() => {
                                HSStaticMethods.autoInit();
                              });
                            });
                          </script>

                          <slot />
                        
                      

autoInit filters stale collection entries and skips nodes that already have plugin instances. That makes repeated route-level scans practical.

Choose imports by the level of control you need

For a full Preline UI installation, preline/non-auto is the best Svelte default. It gives you HSStaticMethods and plugin classes without depending on browser script or plugin auto-entry page-load timing.

preline.ts
                        
                          import { HSStaticMethods } from "preline/non-auto";

                          HSStaticMethods.autoInit(["dropdown", "overlay"]);
                          HSStaticMethods.cleanCollection(["dropdown", "overlay"]);
                        
                      

If you want the class for one plugin from the full package, import that class from preline/non-auto. This keeps the example aligned with the package's declared TypeScript surface.

dropdown.ts
                        
                          import { HSDropdown } from "preline/non-auto";

                          HSDropdown.autoInit();
                        
                      

Single plugin packages keep small Svelte surfaces focused

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 Svelte surface only needs one or two interactive primitives.

Terminal
                        
                          npm install @preline/dropdown
                        
                      
Dropdown.svelte
                        
                          <script lang="ts">
                            import { onMount, tick } from "svelte";
                            import HSDropdown from "@preline/dropdown/non-auto";

                            onMount(() => {
                              tick().then(() => {
                                HSDropdown.autoInit();
                              });
                            });
                          </script>
                        
                      

In that single-package setup, the auto entry is import "@preline/dropdown". Use it for simple static pages. In Svelte components and SvelteKit routes, /non-auto keeps initialization aligned with Svelte lifecycle timing.

Use Svelte actions for manual instances

A Svelte action is a natural fit when one element owns one Preline UI plugin instance. The action receives the DOM node, creates the plugin instance, and returns a destroy hook that Svelte calls when the node is removed.

Dropdown.svelte
                        
                          <script lang="ts">
                            import { HSDropdown, type IHTMLElementFloatingUI } from "preline/non-auto";

                            function prelineDropdown(node: HTMLElement) {
                              const dropdown = new HSDropdown(node as unknown as IHTMLElementFloatingUI);

                              return {
                                destroy() {
                                  dropdown.destroy();
                                },
                              };
                            }
                          </script>

                          <div use:prelineDropdown class="hs-dropdown relative inline-flex">
                            ...
                          </div>
                        
                      

Cleanup matters because Preline UI keeps registries

Preline UI stores plugin instances in internal collections such as window.$hsDropdownCollection. That registry lets plugins coordinate in plain HTML, Svelte, and other environments without framework context.

In Svelte, the practical rule is simple: actions should destroy manual instances, and route-level scans should clean collections only when you intentionally remove a group of initialized markup.

Cleanup
                        
                          HSStaticMethods.cleanCollection("dropdown");
                          HSStaticMethods.cleanCollection(["dropdown", "overlay"]);
                        
                      

Optional dependencies only matter for the plugins that use them

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.

The practical checklist

  • Use preline/non-auto in Svelte when you need explicit lifecycle control.
  • Run autoInit in onMount after tick, and keep the callback synchronous if it returns cleanup.
  • Use afterNavigate plus tick for SvelteKit routes.
  • Use Svelte actions for reusable components that own one plugin root.
  • Call destroy() for manual instances and cleanCollection() when removing initialized groups of markup.
  • Install optional third-party dependencies only for the plugins that need them, such as datatables.net for Datatable or noUiSlider for Range Slider.

© 2026 Preline Labs.