
Security News
Axios Maintainer Confirms Social Engineering Attack Behind npm Compromise
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.
Examples | API | Quick Start | Feature Tracker | Sandbox | Flexlayout
This is Flexycakes, a fork of FlexLayout with enhanced features including pin/unpin functionality for panels. Flexycakes extends the original FlexLayout capabilities with additional user interface improvements and workflow optimizations.
🚀 Exciting News! We're launching a paid bounty system to support young developers in the open source community.
What we're working on:
Stay tuned: Join our Discord community for real-time updates and early access to bounty opportunities!
Install Flexycakes from npm:
npm install flexycakes
or using yarn:
yarn add flexycakes
or using pnpm:
pnpm add flexycakes
Import the components:
import { Layout, Model } from "flexycakes";
Include a theme:
Option A: Import in your JavaScript code:
import "flexycakes/style/light.css";
Option B: Link in your HTML:
<link rel="stylesheet" href="/style/light.css" />
Optional: For dynamic theming, see Theme Switching
If you're contributing to Flexycakes or want to develop locally:
Clone the repository:
git clone https://github.com/powerdragonfire/flexycakes.git
cd flexycakes
Install dependencies:
pnpm install
Create a symbolic link:
# Build the library first
pnpm build
# Create global link
npm link
# or with pnpm
pnpm link --global
Link in your project:
cd /path/to/your/project
npm link flexycakes
# or with pnpm
pnpm link --global flexycakes
Start development mode:
# In flexycakes directory
pnpm dev
This will watch for changes and rebuild automatically.
The <Layout> component renders the tabsets and splitters. Here's what you need:
| Prop | Type | Description |
|---|---|---|
model | Model | The layout model containing the structure |
factory | Function | Creates React components for each tab |
💡 Tip: See Optional Layout Props for additional configuration options.
The model is a tree of Node objects that define your layout structure:
Model.fromJson(jsonObject)model.toJson()The factory function takes a Node object and returns the React component to render in that tab.
// Define your layout structure
const json = {
global: {},
borders: [],
layout: {
type: "row",
weight: 100,
children: [
{
type: "tabset",
weight: 50,
children: [
{
type: "tab",
name: "Dashboard",
component: "dashboard",
},
],
},
{
type: "tabset",
weight: 50,
children: [
{
type: "tab",
name: "Settings",
component: "settings",
},
],
},
],
},
};
// Create your app
const model = Model.fromJson(json);
function App() {
const factory = (node) => {
const component = node.getComponent();
switch (component) {
case "dashboard":
return <DashboardComponent />;
case "settings":
return <SettingsComponent />;
default:
return <div>{node.getName()}</div>;
}
};
return <Layout model={model} factory={factory} />;
}
🎮 Try it live: CodeSandbox Demo | TypeScript Example
The model JSON has 4 main sections:
| Section | Required | Description |
|---|---|---|
global | ❌ | Global layout options |
layout | ✅ | Main layout hierarchy |
borders | ❌ | Edge panels ("top", "bottom", "left", "right") |
popouts | ❌ | External window definitions |
rootOrientationVertical is set)enableDeleteWhenEmpty: false)borders section
💡 Pro Tip: Use the demo app to visually create layouts, then export the JSON via 'Show Layout JSON in console'.
Node weights determine relative sizing:
light.css - Clean light themedark.css - Dark mode themegray.css - Neutral gray themeunderline.css - Minimal underline stylerounded.css - Rounded corners themecombined.css - All themes in one fileUse the combined.css theme for runtime switching:
// Setup with theme container
<div ref={containerRef} className="flexlayout__theme_light">
<Layout model={model} factory={factory} />
</div>;
// Change theme programmatically
containerRef.current.className = "flexlayout__theme_dark";
Customize individual tabs with onRenderTab:
const onRenderTab = (node, renderValues) => {
// renderValues.leading = <Icon />; (red area)
// renderValues.content += " *"; (green area)
renderValues.buttons.push(<MenuIcon key="menu" />); // yellow area
};
<Layout model={model} factory={factory} onRenderTab={onRenderTab} />;
Customize tabset headers with onRenderTabSet:
const onRenderTabSet = (node, renderValues) => {
// Add persistent buttons (red area)
renderValues.stickyButtons.push(
<button key="add" onClick={() => addNewTab(node)}>
+
</button>,
);
// Add contextual buttons (green area)
renderValues.buttons.push(<SettingsIcon key="settings" />);
};
All layout changes happen through actions via Model.doAction():
// Add a new tab
model.doAction(
Actions.addNode(
{ type: "tab", component: "grid", name: "New Grid" },
"targetTabsetId",
DockLocation.CENTER,
0, // position (use -1 for end)
),
);
// Update global settings
model.doAction(
Actions.updateModelAttributes({
splitterSize: 40,
}),
);
📚 Reference: Full Actions API
Handle tab lifecycle events:
function MyComponent({ node }) {
useEffect(() => {
// Listen for resize events
node.setEventListener("resize", ({ rect }) => {
console.log("Tab resized:", rect);
});
// Save data before serialization
node.setEventListener("save", () => {
node.getConfig().myData = getCurrentData();
});
// Handle visibility changes
node.setEventListener("visibility", ({ visible }) => {
if (visible) startUpdates();
else stopUpdates();
});
}, [node]);
}
| Event | Parameters | Description |
|---|---|---|
resize | {rect} | Tab resized during layout |
close | none | Tab is being closed |
visibility | {visible} | Tab visibility changed |
save | none | Before serialization to JSON |
Render tabs in external browser windows for multi-monitor setups.
popout.html to your public directoryenablePopout: true to tab definitionsPopout windows use a different document and window. Access them via:
function PopoutComponent() {
const selfRef = useRef();
const handleEvent = () => {
// ❌ Wrong - uses main window
document.addEventListener("click", handler);
// ✅ Correct - uses popout window
const popoutDoc = selfRef.current.ownerDocument;
const popoutWindow = popoutDoc.defaultView;
popoutDoc.addEventListener("click", handler);
};
return <div ref={selfRef}>Content</div>;
}
📖 Deep Dive: React Portals in Popups
# Install dependencies
pnpm install
# Start development server
pnpm dev
# Run tests (in separate terminal)
pnpm playwright
# Build for distribution
pnpm build
The built files will be in the dist/ directory.
Complete list of optional props for the <Layout> component:
TypeScript interfaces for all configuration objects:
Programmatically add tabs using Layout component methods:
// Get reference to Layout component
const layoutRef = useRef();
// Add tab to specific tabset
layoutRef.current.addTabToTabSet("NAVIGATION", {
type: "tab",
component: "grid",
name: "New Grid",
});
Remove tabs entirely for a pure splitter interface:
const json = {
global: {
tabSetEnableTabStrip: false,
},
// ... rest of layout
};
// Auto-generated IDs are UUIDs
const autoId = "#0c459064-8dee-444e-8636-eb9ab910fb27";
// Get node ID
const nodeId = node.getId();
// Use in actions
model.doAction(Actions.selectTab(nodeId));
Comparing Flexycakes with other React layout managers:
| Library | Repository | Key Features |
|---|---|---|
| Flexycakes | powerdragonfire/flexycakes | Enhanced FlexLayout with pin/unpin |
| rc-dock | ticlo/rc-dock | Dock-style layouts |
| Dockview | dockview.dev | Modern docking solution |
| Lumino | jupyterlab/lumino | JupyterLab's layout system |
| Golden Layout | golden-layout/golden-layout | Multi-window layouts |
| React Mosaic | nomcopter/react-mosaic | Tiling window manager |
Flexycakes is a drop-in replacement for FlexLayout with additional features:
Update package:
npm uninstall flexlayout-react
npm install flexycakes
Update imports:
// Before
import FlexLayout from "flexlayout-react";
// After
import { Layout, Model } from "flexycakes";
Update CSS imports:
// Before
import "flexlayout-react/style/light.css";
// After
import "flexycakes/style/light.css";
FAQs
Community fork of caplin/FlexLayout (ISC). Not affiliated.
We found that flexycakes demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.