fluid-box-prototype Svelte Themes

Fluid Box Prototype

A lightweight Svelte 5 layout system based on proportions instead of rigid grids.

FluidBox Icon

FluidBox

Fluid, adaptive panel layouts for Svelte — drag, resize, and persist with zero configuration.


The FluidBox Philosophy

FluidBox is built around one idea: layouts should bend to content, not the other way around.

Most layout libraries give you a rigid grid. FluidBox gives you proportions. A slice is not 300 pixels wide — it is twice as wide as its neighbour. When content changes, the layout breathes.

Principles:

  • Fluid over fixed — flex proportions, not pixel widths. A x={2} slice is always twice the size of a x={1} slice, regardless of screen size.
  • Two attributes, infinite layoutsx for horizontal, y for vertical. That's the entire API for describing a layout tree.
  • Progressive control — works with zero options. Drag handles, persistence, and min-sizes are opt-in, not required.
  • No dependencies — pure Svelte 5 + vanilla DOM. No external layout libraries, no CSS frameworks.
  • Drag to resize — users own their layout. Resize handles appear on hover between any two adjacent slices.
  • Persistent — pass a layoutKey and the user's resize preferences survive page reloads automatically.

Installation

FluidBox is currently a local component library. Copy the components into your Svelte 5 project:

cp src/Components/FluidBox.svelte your-project/src/Components/
cp src/Components/FluidSlice.svelte your-project/src/Components/
cp src/stores/layoutStore.js your-project/src/stores/

Quick Start

<script>
  import FluidBox from './Components/FluidBox.svelte';
  import FluidSlice from './Components/FluidSlice.svelte';
</script>

<FluidBox>
  <FluidSlice x={1} background="#e3f2fd" />
  <FluidSlice x={2} background="#bbdefb" />
  <FluidSlice y={1} background="#90caf9" />
</FluidBox>

The layout produced by the above:

┌──────────────────────────────────────┐
│  x=1   │           x=2              │
│        │                            │
├────────┴────────────────────────────┤
│                 y=1                 │
└──────────────────────────────────────┘

Layout algorithm: each time a child has a different axis than the previous one, everything built so far collapses into a single unit and the new child takes its proportional flex space alongside it — in the direction the new child specifies. This is fully recursive and unbounded: you can alternate axes as many times as you like and each axis change produces one more level of nesting.


API

<FluidBox>

Prop Type Default Description
animated boolean true Enable CSS transitions on layout changes
resizable boolean true Show drag handles between adjacent slices
layoutKey string|null null localStorage key for auto-saving resize state
initialLayout object {} Initial flex values map, e.g. { "0": 1.5, "1": 0.5 }
dragSensitivity number 1 Drag multiplier — 1 = 1:1 pixels, 2 = twice as fast

Exposed method (via bind:this):

<FluidBox bind:this={box} />
<button onclick={() => console.log(box.getLayout())}>Export</button>

getLayout() returns a plain object mapping slice keys to their current flex values.


<FluidSlice>

Prop Type Default Description
x number|null null Horizontal flex weight
y number|null null Vertical flex weight
animated boolean true Transition on flex changes
background string "yellow" CSS background-color
minSize number|null null Minimum pixel size during drag
slicekey string|null null Stable key for layout persistence (recommended when using layoutKey)

Only one of x or y should be provided per slice. The value is the flex weight relative to sibling slices.


Layout Persistence

<FluidBox layoutKey="my-dashboard">
  <FluidSlice x={1} slicekey="sidebar" minSize={120} />
  <FluidSlice x={3} slicekey="main" />
  <FluidSlice y={1} slicekey="panel" minSize={80} />
</FluidBox>

The user's resize preferences are saved to localStorage under "my-dashboard" automatically. On the next page load, the layout is restored. Use slicekey props to keep layout stable when slices are added or removed.


Nested Layouts

FluidBox supports recursive nesting — place a FluidBox inside a FluidSlice:

<FluidBox>
  <FluidSlice x={1} background="#e3f2fd" />
  <FluidSlice x={2}>
    <FluidBox>
      <FluidSlice y={1} background="#bbdefb" />
      <FluidSlice y={1} background="#90caf9" />
    </FluidBox>
  </FluidSlice>
</FluidBox>
┌──────────────────────────────┐
│        │    top panel        │
│        ├─────────────────────│
│  x=1   │    bottom panel     │
└──────────────────────────────┘

Comparison

Library Approach Bundle contribution¹ Drag resize Persistence Nesting Framework
golden-layout JSON config, tab groups ~180 KB yes yes yes Vanilla
react-mosaic React, binary tree model ~90 KB yes no yes React
FluidBox Declarative, 2 attributes ~5 KB yes yes yes Svelte 5

¹ Bundle contribution = the code each library adds to your app bundle (minified, no runtime/framework overhead).
FluidBox component source files total 17.8 KB unminified (FluidBox.svelte 16.2 KB + FluidSlice.svelte 0.8 KB + FluidDivider.svelte 0.1 KB + layoutStore.js 0.6 KB). After Svelte compilation and minification the contribution to a host app bundle is **5–6 KB** (~2–3 KB gzipped). The Svelte runtime is excluded since it is a peer dependency already present in the host app.
golden-layout and react-mosaic figures are their published minified bundles including their own runtime code.


Development

npm install
npm run dev      # start dev server
npm run build    # production build
npm run preview  # preview production build

License

MIT — by Massimo Moffa

Top categories

Loading Svelte Themes