Panekit is a headless window manager toolkit for Svelte 5.
The idea behind Panekit originates from old school MDI style GUI from the era of Java Swing and Visual Fox Pro, with a modern touch in the form of tiling modes and a declarative style.
If you are planning to use this, beware of the following:
This library has a peer dependency on svelte 5, specifically 5.29 or newer, as it uses attachments to work.
npm i panekit
First, wrap your application with the PanekitProvider
. This creates the context needed for window management and sets up the portal target where panes will be rendered.
<script>
import { PanekitProvider } from 'panekit';
</script>
<PanekitProvider>
<div class="h-dvh w-dvw">
<!-- Your app content -->
</div>
</PanekitProvider>
Panes are composed of three main components: Root
, Handle
, and Content
.
<script>
import { Pane } from 'panekit';
let count = $state(0);
</script>
<Pane.Root class="rounded-md border bg-white shadow-md">
<Pane.Handle class="flex items-center justify-center">
Window Title
</Pane.Handle>
<Pane.Content class="flex items-center justify-center">
<button onclick={() => (count += 1)}>
Count: {count}
</button>
</Pane.Content>
</Pane.Root>
PanekitProvider
The root provider component that must wrap your application.
Props:
dragModifier?: DragModifier
- Modifier key required for full-pane dragging ('altKey' | 'ctrlKey' | 'shiftKey' | 'metaKey'
). Default: 'altKey'
Pane.Root
The main pane container. Panes are draggable and resizable by default.
Props:
size?: { width: number; height: number }
- Initial size of the pane. Default: { width: 200, height: 200 }
paneId?: string
- Custom ID for the pane. Auto-generated if not providedportalId?: string
- Target a specific portal by IDdragModifier?: DragModifier
- Override the global drag modifier for this paneBehavior:
Pane.Handle
The draggable header/title bar of the pane.
Props:
Pane.Content
The main content area of the pane.
Props:
Pane.PortalTarget
Portal target component for rendering panes. The provider includes one by default, but you can create additional targets.
Props:
portalId?: string
- Unique identifier for this portal targetYou can create multiple portal targets to render panes in different areas:
<PanekitProvider>
<div class="flex h-screen">
<div class="flex-1">
<Pane.PortalTarget portalId="left-panel" />
</div>
<div class="flex-1">
<Pane.PortalTarget portalId="right-panel" />
</div>
</div>
<!-- This pane will render in the right panel -->
<Pane.Root portalId="right-panel">
<Pane.Handle>Right Side Window</Pane.Handle>
<Pane.Content>Content here</Pane.Content>
</Pane.Root>
</PanekitProvider>
The library provides a (broken, leaky) pane manager for programmatic control:
<script>
import { usePM } from 'panekit';
const paneManager = usePM();
function focusPane(id) {
paneManager.focusPane(id);
}
function blurAllPanes() {
paneManager.blurAll();
}
</script>
Panekit is headless and provides minimal default styling. It's designed with utility classes in mind (Tailwind won, accept it), classes are deduplicated and merged via the cn
helper internally, so svelte 5 cslx classes should still work just fine.
You can style based on data attributes if needed. each component has data attributes you can hook into for styling:
[data-pane]
- Applied to pane root elements[data-pane-handle]
- Applied to handle elements [data-pane-content]
- Applied to content elements[data-pane-portal-target]
- Applied to portal target elementsMore data attributes will be added so that you can style based on drag state, resize state, focus state and so on. I am just lazy so I didn't do it yet.
I honestly have no idea. probably ones that have CSS has:
and above.