npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@csedl/hotwire-svelte-helpers

v4.2.1

Published

Hotwire + Svelte helpers for Rails: Stimulus floating dropdowns/toolips + Svelte global panels/modals + RTurbo-friendly utilities. Build together with the rubygem svelte-on-rails and its npm-package.

Readme

Hotwire Svelte Helpers

Helpers for building overlays — such as dropdowns, tooltips, and modals — with Floating UI, Stimulus, and Svelte in a Hotwire/Turbo environment.

Includes flexible Svelte form components that work with the svelte-on-rails gem and can be imported directly from the package or copied into your project.

A small toolkit for building more interactive Rails apps with Hotwire and Svelte.

Links:

Setup

import { HotwireSvelteHelpers } from "@csedl/hotwire-svelte-helpers/setup"
HotwireSvelteHelpers.debug = true
HotwireSvelteHelpers.initializeOverlays()

cleanMount()

Interaction with (Svelte) components can lead to orphaned instances. This can happen when the unmount event does not happen, for example when the underlaying DOM element disappears which can happen in a Hotwire Environemnt.

For this here is a double security. CleanMount() adds the instance to a global store and then executes mount().

import {cleanMount} from "@csedl/hotwire-svelte-helpers";
cleanMount(AnySvelteComponent, { target: cleanMountDemoTag, ...});

Next, you must add something like

import { unmountAllDetached } from '@csedl/hotwire-svelte-helpers'
document.addEventListener('turbo:render', () => {
  unmountAllDetached()
})

to your application.js. This will check for detached instances and unmount them.

Dropdown Example

<div data-controller="csedl-dropdown" data-panel-id="dropdown-panel-3h5k7l4">
    Button
</div>
<div id="dropdown-panel-3h5k7l4" class="dropdownSvelte-panel-example-class" style="display: none;">
    ... any content
</div>

body#overlays-box Tag

Svelte dropdown panels are mounted into #overlays-box, a shared overlay container appended directly to document.body. If #overlays-box does not exist, it is created automatically. This keeps overlays at the root level to avoid most z-index and clipping issues, while keeping the DOM cleaner than mounting panels directly into body.

This aligns to the behaviour of the stimulus side

Svelte Dropdowns

There are some default components included, which can be used to build Svelte Dropdowns. Check the online example app for more details.

What it does

  • When the button is clicked, it toggles the display style on the panel and places the panel using floating-ui.
  • When the panel is open, the has-open-panel class is added to the button, otherwise it is removed.
  • Adds functionality to close all panels when clicking outside a panel.
  • When a data-src attribute is given to the panel, on opening the panel, it fires a xhr request and replaces the content (fetched by selector: .content within the panel-element) by the response.
  • This all works with stacked panels too (panel in panel).

Close on click outside

When a dropdownSvelte is open, it closes when clicking outside a panel.

This behaviour can be stopped by:

  • The clicked element or its parent elements has the data-dropdownSvelte-persist (not: data-dropdownSvelte-persist="false") attribute.
  • the event has the attribute event.detail.dataDropdownPersist set to true.

Notes

Important: When creating or initializing the dropdown, always call the initialize function before attaching a listener to the panel's close event. The initialize function adds a close event listener to the panel that executes the onPanelClose function. If your custom close function destroys the panel, this has to be done after the onPanelClose is fired by the close event.

Options

  • If there is an element with ID arrow inside the dropdownSvelte panel, it is treated as described on floating-ui.
  • The data-placement attribute on the panel can be used to control positioning, see floating-ui/placements.

Events

Events on the button element:

  • place-panel places the panel, and, if present, the arrow element, by floating-ui.

Events the panel element:

  • close closes the panel.
  • place-me like place-panel on the button.

Event Triggers on the button element:

  • before-open-panel
  • after-close-panel

Event Triggers on the panel element:

  • before-open

Helpers

If the panels are rendered to a different location than the button (see z-index on rails-app), within a scrollable (e.g.) container, the button would scroll away from the panel. For such cases, add this both data-attributes to the scrollable element:

<div data-controller="csedl-place-dropdownSvelte-panels" data-on="scroll" data-run-after="500" style="overflow: scroll;">
    ...
</div>

Now, on scrolling, it searches for all dropdownSvelte-buttons (by class-name has-open-panel) and triggers the place-panel event there.

Options

data-on Attribute:

  • scroll triggered by scroll Event of the given element.
  • resize-observer triggered by ResizeObserver on the given element.

data-run-after Attribute:

  • Milliseconds as number.

This is only relevant if you have things like css transition enabled, so that after the above resize events are fired, subsequent events are needed. It will fire the place-panel after the last resize/scroll event within the given time.

Tip Turn console-debug-log on (see configs) and check how events are working.

Explanation

What these helpers mainly do is to find all the dropdowns by the has-open-panel class and fire the place-panel event. But within the helper, things like performance optimisation are done: it searches once and places the panels multiple times.

Tooltip

<span data-controller="csedl-tooltip" data-panel-id="tooltip-123" data-delay="0.2">
    Text-with-tooltip
</span>
<div id="tooltip-123" class="tooltip-panel" style="display: none;">
    <div id="arrow"></div>
    ... any content
</div>

makes a tooltip.

It adds the class tooltip-is-visible to the tooltip label while the tooltip is visible.

data-src attribute is working similar to dropdownSvelte

Stimulus Usage

This package uses Stimulus unconventionally to initialize and toggle external dropdownSvelte or tooltip panels (via data-panel-id) rather than managing child elements within the controller’s scope, as is typical in Stimulus documentation.

The same result could be achieved using MutationObserver and plain JavaScript.

Stimulus was chosen because this package is intended for use with Hotwire/Turbo where Stimulus already is installed. It has a modest footprint of just 10 KB. It also holds many configs for MutationObserver, especially for our exact purpose.

License

MIT