PaneForge Documentation

repository·main·Indexed 20 days ago

https://github.com/svecosystem/paneforge

A Svelte library for creating highly customizable, accessible, and resizable pane layouts. It provides a hierarchical component model consisting of PaneGroup for layout management, Pane for individual resizable areas, and PaneResizer for draggable handles. Features include support for nested groups, collapsible panes, layout persistence via local storage or custom storage interfaces, and an imperative API for programmatic control.

Tokens
11K
Snippets
41
Records
50
Agent score
70%

What's inside PaneForge

  1. Overview of PaneForge features

    main

    PaneForge is a library of Svelte components designed for creating resizable pane layouts. It is inspired by react-resizable-panels and provides the following capabilities:

    • Resizable Panes: Users can resize panes by dragging resizers between them.
    • Nested Groups: Supports nesting groups of panes within other groups to build complex, hierarchical layouts.
    • Customization: Layout appearance and behavior can be modified via Svelte props and CSS.
    • Persistence: Supports persisting pane layouts across page loads using LocalStorage or cookies.
    • Accessibility: Designed with accessibility in mind for users of assistive technologies.
  2. Persist PaneGroup layouts with custom storage

    main

    By default, providing an autoSaveId saves the layout to local storage. To use a custom storage mechanism (e.g., a database or session storage), provide a storage object that implements the PaneGroupStorage interface:

    export type PaneGroupStorage = {
    	getItem(name: string): string | null;
    	setItem(name: string, value: string): void;
    };
    export type PaneGroupStorage = {
    	/** Retrieves the item from storage */
    	getItem(name: string): string | null;
    	/** Sets the item to storage */
    	setItem(name: string, value: string): void;
    };
  3. Target components using data attributes

    main

    Every element rendered by PaneForge includes specific data attributes. You can use these attributes in your global CSS to target components across your entire application without needing to manually add classes to every instance. Refer to the specific component's API reference to find the exact data attribute names (e.g., [data-pane-group]).

    /* Example: Targeting all PaneGroups globally */
    [data-pane-group] {
    	height: 3rem;
    	width: 100%;
    	background-color: #3182ce;
    	color: #fff;
    }
  4. How PaneForge components work together

    main

    PaneForge uses a hierarchical component model to build layouts:

    1. PaneGroup: The top-level container that manages the layout logic and direction (horizontal or vertical).
    2. Pane: Represents an individual resizable area within the group. It accepts a defaultSize prop to define its initial footprint.
    3. PaneResizer: The interactive element placed between Pane components. Users drag this to adjust the relative sizes of adjacent panes.

    This structure allows for Nested Groups, where a PaneGroup can be placed inside a Pane of another group, enabling complex, multi-dimensional layouts.

  5. Create collapsible panes in PaneForge

    main

    To create collapsible panes, use the collapsible and collapsedSize props on the Pane component.

    • collapsible={true}: Enables the ability to collapse the pane.
    • collapsedSize={number}: Defines the size of the pane when it is in its collapsed state.

    You can react to state changes using the onCollapse and onExpand callback props. Additionally, you can capture a reference to the Pane component instance using bind:this to programmatically control the pane via its .collapse() and .expand() methods.

    <script lang="ts">
    	import { PaneGroup, Pane, PaneResizer } from "paneforge";
    
    	let paneOne: ReturnType<typeof Pane>;
    	let collapsed = $state(false);
    </script>
    
    {#if collapsed}
    	<button onclick={paneOne.expand}> Expand Pane One </button>
    {:else}
    	<button onclick={paneOne.collapse}> Collapse Pane One </button>
    {/if}
    
    <PaneGroup direction="horizontal">
    	<Pane
    		defaultSize={50}
    		collapsedSize={5}
    		collapsible={true}
    		minSize={15}
    		bind:this={paneOne}
    		onCollapse={() => (collapsed = true)}
    		onExpand={() => (collapsed = false)}
    	/>
    	<PaneResizer />
    	<Pane defaultSize={50}>
    		<PaneGroup direction="vertical">
    			<Pane defaultSize={50} />
    			<PaneResizer />
    			<Pane defaultSize={50} />
    		</PaneGroup>
    	</Pane>
    </PaneGroup>
  6. Persist pane layouts using Cookies for SSR-friendly layouts

    main

    Because Local Storage is unavailable during Server-Side Rendering (SSR), layouts may flicker when the page first loads. To prevent this, you can use cookies to persist pane sizes.

    1. On the Server: Read the layout from the cookie (using the key PaneForge:layout) in your load function and pass it to the component.
    2. On the Client: Use the onLayoutChange prop on the PaneGroup component to update the cookie whenever the user resizes a pane.

    Note: The cookie value is stored as a JSON string representing an array of numbers (the pane sizes).

    import type { PageServerLoad } from "./$types";
    
    export const load: PageServerLoad = async (event) => {
    	let layout = event.cookies.get("PaneForge:layout");
    	if (layout) {
    		layout = JSON.parse(layout);
    	}
    
    	return {
    		layout,
    	};
    };
    <script lang="ts">
    	import { PaneGroup, Pane, PaneResizer } from "paneforge";
    
    	let { data } = $props();
    
    	function onLayoutChange(sizes: number[]) {
    		document.cookie = `PaneForge:layout=${JSON.stringify(sizes)}`;
    	}
    </script>
    
    <PaneGroup direction="horizontal" {onLayoutChange}>
    	<Pane defaultSize={data.layout ? data.layout[0] : 50} />
    	<PaneResizer />
    	<Pane defaultSize={data.layout ? data.layout[1] : 50} />
    </PaneGroup>
  7. Persist pane layouts using Local Storage

    main

    To automatically save and restore the layout of panes within a PaneGroup using the browser's local storage, provide a unique string to the autoSaveId prop. This allows the pane sizes to persist across page reloads without manual state management.

    <script lang="ts">
    	import { PaneGroup, Pane, PaneResizer } from "paneforge";
    </script>
    
    <PaneGroup direction="horizontal" autoSaveId="someGroupId">
    	<Pane defaultSize={50} />
    	<PaneResizer />
    	<Pane defaultSize={50} />
    </PaneGroup>
  8. Apply global styles via CSS classes

    main

    You can apply global styles to PaneForge components by defining a standard CSS class and then passing that class name to the component via the class prop. This is useful for maintaining a consistent design system across your application.

    /* 1. Define global styles in your CSS file */
    .pane-group {
    	height: 3rem;
    	width: 100%;
    	background-color: #3182ce;
    	color: #fff;
    }
    <!-- 2. Use the class with a component -->
    <script lang="ts">
    	import { PaneGroup } from "paneforge";
    </script>
    
    <PaneGroup class="pane-group">Click me</PaneGroup>
  9. Build and preview for production

    main

    To prepare your application for production, run the build script. Once the build is complete, you can use the preview script to run a local server that serves the production build for testing.

    npm run build
    
    # preview the production build
    npm run preview
  10. Start the development server

    main

    After creating your project and installing dependencies (via npm install, pnpm install, or yarn), use the dev script to start the local development server. You can use the --open flag to automatically open the application in your default browser.

    npm run dev
    
    # or start the server and open the app in a new browser tab
    npm run dev -- --open