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 🙏

© 2025 – Pkg Stats / Ryan Hefner

layout-manager-react

v0.0.16

Published

A modern React layout manager using flexbox with percentage-based sizing

Readme

Layout Manager React

A modern React layout manager using flexbox with percentage-based sizing, similar to FlexLayout but simpler and more performant.

🚀 Live Demo

Try it out: https://hrashkan.github.io/layout-manager-demo/

Features

  • 🎯 Flexbox-based: Uses CSS flexbox instead of absolute positioning
  • 📏 Percentage sizing: Responsive layout with percentage-based dimensions
  • 🔄 Drag & Drop: Full drag and drop support with 4 drop zones (center, left, right, top/bottom)
  • 📐 Resizable: Resize tabsets with smooth mouse tracking
  • 🌍 RTL/LTR Support: Full right-to-left and left-to-right direction support
  • 💾 Persistent Storage: Automatic localStorage persistence with debounced saving
  • 🎨 Customizable: Easy to style and customize
  • Performance: Optimized for best performance
  • 🔒 Type Safe: Full TypeScript support

Installation

npm install layout-manager-react

To update to the latest version:

npm install layout-manager-react@latest
# or
npm update layout-manager-react

Bundle Size: Check the package size on Bundlephobia

Quick Start

import React, { useState } from "react";
import { Layout, LayoutModel } from "layout-manager-react";
import "layout-manager-react/dist/style.css";

const App: React.FC = () => {
  const [model, setModel] = useState<LayoutModel>({
    layout: {
      id: "root",
      type: "row",
      children: [
        {
          id: "tabset-1",
          type: "tabset",
          children: [
            {
              id: "tab-1",
              type: "tab",
              component: "dashboard",
              name: "Dashboard",
              enableClose: true,
              enableDrag: true,
            },
          ],
          selected: 0,
          flex: 1,
        },
      ],
      flex: 1,
    },
    global: {
      splitterSize: 8,
      direction: "ltr",
    },
  });

  const factory = (node: any) => {
    switch (node.component) {
      case "dashboard":
        return <div>Dashboard Content</div>;
      default:
        return <div>Default Content</div>;
    }
  };

  return (
    <div style={{ height: "100vh", width: "100vw" }}>
      <Layout model={model} factory={factory} onModelChange={setModel} />
    </div>
  );
};

export default App;

Important: Don't forget to import the CSS file!

CSS Import Options

Option 1: Direct import (Recommended)

import "layout-manager-react/dist/style.css";

Option 2: In your main entry file (e.g., app.tsx, _app.tsx, or main.tsx)

// Next.js App Router (app/layout.tsx)
import "layout-manager-react/dist/style.css";

// Next.js Pages Router (_app.tsx)
import "layout-manager-react/dist/style.css";

// Vite/React (main.tsx)
import "layout-manager-react/dist/style.css";

Option 3: In your global CSS file

/* styles.css or globals.css */
@import "layout-manager-react/dist/style.css";

Next.js Specific

For Next.js App Router (app/ directory):

// app/layout.tsx or app/page.tsx
import "layout-manager-react/dist/style.css";
import { Layout } from "layout-manager-react";

For Next.js Pages Router (pages/ directory):

// pages/_app.tsx or any page component
import "layout-manager-react/dist/style.css";
import { Layout } from "layout-manager-react";

Note: Make sure to import the CSS in a client component ("use client" directive) or in a file that's processed by Next.js.

Usage with Helper Functions

For easier layout creation, use the helper functions:

import React, { useState } from "react";
import {
  Layout,
  createLayoutModel,
  createTab,
  createTabSet,
  createRow,
  createColumn,
  LayoutModel,
} from "layout-manager-react";
import "layout-manager-react/dist/style.css";

const App: React.FC = () => {
  const [model, setModel] = useState<LayoutModel>(
    createLayoutModel(
      createRow("root", [
        createTabSet("left-tabs", [
          createTab("tab-1", "dashboard", "Dashboard"),
          createTab("tab-2", "settings", "Settings"),
        ]),
      ])
    )
  );

  const factory = (node: any) => {
    switch (node.component) {
      case "dashboard":
        return <div>Dashboard</div>;
      case "settings":
        return <div>Settings</div>;
      default:
        return <div>Unknown</div>;
    }
  };

  return (
    <div style={{ height: "100vh" }}>
      <Layout model={model} factory={factory} onModelChange={setModel} />
    </div>
  );
};

API Reference

Layout Component

The main layout component.

Props

| Prop | Type | Required | Description | | ---------------------- | --------------------------------------- | -------- | ----------------------------------------- | | model | LayoutModel | Yes | The layout model containing the structure | | factory | (node: LayoutNode) => React.ReactNode | Yes | Factory function to render tab content | | onModelChange | (model: LayoutModel) => void | No | Callback when layout changes | | onAction | (action: LayoutAction) => void | No | Callback for layout actions | | storage | StorageOptions | No | Storage configuration | | className | string | No | Additional CSS class | | style | React.CSSProperties | No | Additional inline styles | | closeIcon | React.ReactElement | No | Custom close icon for all tabs | | closeButtonClassName | string | No | Custom CSS class for close buttons |

LayoutNode Types

  • row: Horizontal container for organizing tabsets side by side
  • column: Vertical container for organizing tabsets vertically
  • tabset: Container for tabs
  • tab: Individual tab content node

Helper Functions

createLayoutModel(layout: LayoutNode, global?: GlobalConfig): LayoutModel

Creates a complete layout model with optional global configuration.

const model = createLayoutModel(rootNode, {
  splitterSize: 8,
  direction: "ltr",
});

createRow(id: string, children: LayoutNode[], flex?: number): LayoutNode

Creates a row node (horizontal container).

const row = createRow("root", [tabset1, tabset2], 1);

createColumn(id: string, children: LayoutNode[], flex?: number): LayoutNode

Creates a column node (vertical container).

const column = createColumn("col1", [tabset1, tabset2], 0.5);

createTabSet(id: string, children: TabNode[], flex?: number, selected?: number): LayoutNode

Creates a tabset node.

const tabset = createTabSet("tabs", [tab1, tab2], 1, 0);

createTab(id: string, component: string, name: string, options?: TabOptions): TabNode

Creates a tab node.

const tab = createTab("tab1", "dashboard", "Dashboard", {
  enableClose: true,
  enableDrag: true,
});

Direction Support

The layout manager supports both LTR (Left-to-Right) and RTL (Right-to-Left) directions.

Setting Direction

const model = createLayoutModel(layout, {
  direction: "rtl", // or "ltr"
});

Dynamic Direction Changes

const [direction, setDirection] = useState<"ltr" | "rtl">("ltr");

const model = createLayoutModel(layout, {
  direction,
});

// Toggle direction
const toggleDirection = () => {
  setDirection((prev) => (prev === "ltr" ? "rtl" : "ltr"));
};

Features

  • LTR: Default left-to-right layout
  • RTL: Right-to-left layout with reversed row children
  • Dynamic: Change direction at runtime
  • CSS Support: Proper RTL styling with dir attribute

Persistent Storage

The layout manager supports automatic localStorage persistence to save user customizations.

Basic Storage Usage

<Layout
  model={model}
  factory={factory}
  storage={{
    enabled: true,
    key: "my-layout",
    autoSave: true,
    debounceMs: 500,
  }}
/>

Storage Options

| Option | Type | Default | Description | | ------------ | --------- | ----------- | ------------------------------ | | enabled | boolean | false | Enable/disable storage | | key | string | "default" | Storage key for localStorage | | autoSave | boolean | true | Automatically save on changes | | debounceMs | number | 500 | Debounce delay in milliseconds |

Manual Storage Control

import { createLayoutStorage, LayoutModel } from "layout-manager-react";

const storage = createLayoutStorage({ key: "my-layout" });

// Save manually
storage.save(model);

// Load manually
const savedModel: LayoutModel | null = storage.load();

// Clear storage
storage.clear();

// Check if storage exists
if (storage.exists()) {
  // Load saved layout
}

Storage Features

  • Automatic Saving: Changes are automatically saved to localStorage
  • Debounced Writes: Multiple rapid changes are batched to avoid excessive writes
  • Custom Keys: Use different storage keys for multiple layouts
  • Manual Control: Clear storage or disable auto-save as needed

Drag & Drop

Full drag and drop support with 4 drop zones:

  • Center: Add tab to existing tabset
  • Left: Create new tabset to the left (50% width)
  • Right: Create new tabset to the right (50% width)
  • Top/Bottom: Create new tabset above/below (50% height)

Tabs can be dragged by enabling enableDrag: true on the tab node.

Resizing

Tabsets can be resized by dragging the splitter between them. The layout automatically recalculates flex values to maintain proportional sizing.

TypeScript Support

Full TypeScript definitions are included. Import types as needed:

import type {
  LayoutModel,
  LayoutNode,
  LayoutProps,
  LayoutAction,
  LayoutRef,
} from "layout-manager-react";

Styling

The library includes default styles, but you can customize them by overriding CSS classes:

  • .react-flex-layout - Main layout container
  • .react-flex-layout-row - Row container
  • .react-flex-layout-column - Column container
  • .react-flex-layout-tabset - Tabset container
  • .react-flex-layout-tab - Individual tab
  • .react-flex-layout-splitter - Resize splitter

Custom Close Icons

You can customize the close icon for all tabs by passing a custom React element:

const CustomCloseIcon = () => (
  <svg
    width="14"
    height="14"
    viewBox="0 0 24 24"
    fill="none"
    stroke="currentColor"
  >
    <circle cx="12" cy="12" r="10" />
    <line x1="15" y1="9" x2="9" y2="15" />
    <line x1="9" y1="9" x2="15" y2="15" />
  </svg>
);

// ⚠️ Important: Memoize closeIcon to prevent unnecessary re-renders
const memoizedCloseIcon = useMemo(() => <CustomCloseIcon />, []);

<Layout model={model} factory={factory} closeIcon={memoizedCloseIcon} />;

Custom Close Button Styling

Apply custom CSS classes to close buttons:

<Layout
  model={model}
  factory={factory}
  closeButtonClassName="my-custom-close-button"
/>

// In your CSS
.my-custom-close-button {
  border-radius: 50%;
  transition: all 0.2s ease;
}

.my-custom-close-button:hover {
  background-color: #e53935;
  transform: scale(1.1);
}

Examples

See the examples/ directory for more complete examples:

  • basic-usage.tsx - Basic layout setup
  • advanced-usage.tsx - Advanced features with storage and actions

Browser Support

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Edge (latest)

Peer Dependencies

  • react: >=16.8.0
  • react-dom: >=16.8.0

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Repository

GitHub Repository