Introduction
Rows & Columns is a JavaScript layout engine for CSS Grid that works by placing elements directly on grid lines.
This gives precise two-dimensional control over child <div> placement without extra wrapper elements.
Unlike traditional frameworks, Rows & Columns lets you define layouts in HTML or JavaScript while keeping your markup flat and semantic.
You no longer need excessive <div class='row'> or <div class='column'> wrappers, and CSS code is greatly simplified.
THE OLD WAY (DIV SOUP)
To split a column into two rows, most frameworks require an extra wrapper div.
<div class="row">
<div class="col-4">Sidebar</div>
<div class="col-8">
<!-- Wrapper needed for vertical split -->
<div class="column">
<div class="col-6">Top Content</div>
<div class="col-6">Bottom Content</div>
</div>
</div>
</div>
THE ROWSCOLUMNS WAY
No wrappers needed. Layout is defined by grid line placement, keeping HTML flat and semantic.
<div layout="Grid.col(30, (70).row(50, 50))">
<div>Sidebar</div>
<div>Top Content</div>
<div>Bottom Content</div>
</div>
Live Result
The engine automatically calculates positions and sizes using line placement to fit elements into a recursive grid:
GETTING STARTED
Installation
Rowscolumns is zero-dependency and extremely lightweight (~6KB). You can use it with a package manager or directly in the browser.
1. Package Manager (Recommended)
Best for React, Vue, Next.js, Vite, and modern build pipelines.
npx create-vite@latest my-rc-website cd my-rc-website npm install rowscolumns
2. Vanilla HTML/CDN (No Installation required)
To use Rowscolumns in a static HTML file, you must use type="module" or manually download
index.mjs
from the dist folder.
<!-- Import directly from UNPKG (No Installation required)-->
<script type="module">
// 1. Import Engine
import { Engine } from 'https://unpkg.com/rowscolumns/dist/index.mjs';
// 2. Initialize (Starts the observer)
Engine.init();
</script>
<!-- If you manually downloaded the dist folder -->
<script type="module">
// 1. Import the Engine from your built file
import { Engine } from './dist/index.mjs';
// 2. Initialize the Engine
// (This installs the .col/.row extensions and starts the resize listener)
Engine.init();
console.log("RowsColumns Engine Initialized!");
</script>
3. Framework Imports
If you are using a framework, import from the specific sub-package to get the correct wrapper components.
// Import Component + Logic Variables
import { Layout, Grid, lg, sm } from 'rowscolumns/react';
// Import Component + Logic Variables
import { Layout, Grid, lg, sm } from 'rowscolumns/vue';
// Import Standalone Component
import { RowscolumnsComponent } from 'rowscolumns/angular';
// Import Logic
import { Grid, lg, sm } from 'rowscolumns';
CORE CONCEPTS
Grid Basics: Columns & Rows
Before creating grids, it’s important to understand how rows and columns work and the core functionality of the library.
The library extends Number.prototype, defines Grid as a constant set to 100, and supports method chaining.
Unlike many frameworks, this library prioritises CSS Grid over Flexbox, which makes it truly two-dimensional.
Making Columns
Use .col(a, b, c...) to split space horizontally.
<div layout="Grid.col(20, 80)"> <div>20</div> <div>80</div> </div>
Tip : You can make infinite columns Grid.col(10, 10, 10, 10, 10, 10, 10, 10, 10, 10...)
Making Rows
Use .row(a, b, c...) to split space vertically.
<div layout="Grid.row(30, 70)"> <div>30</div> <div>70</div> </div>
Making Grid (Recursion)
You can nest rows inside columns infinitely. Here is a 50/50 split, where the right side is split into 3 rows.
<div layout="Grid.col(50, (50).row(10, 10, 30))"> <div>Left</div> <div>Right 1</div> <div>Right 2</div> <div>Right 3</div> </div>
Responsive Grid
In Rowscolumns, you define the relative weight of columns rather than fixed pixel widths. This allows you to create layouts that breathe naturally as the screen grows, without ever writing a margin or padding rule.
Dynamic Gutter Logic
In this example, we create a layout where the center content stays stable, but the side "gutters" expand on larger screens to keep the content focused.
- On Mobile (sm): The grid behaves as a 12-unit system (1 + 10 + 1). The side gutters are thin, giving the main content maximum room.
- On Desktop (lg): The grid automatically shifts to an 18-unit system (4 + 10 + 4). The content remains centered, while the side gutters grow to create a professional, wide-screen feel.
<!--
The side columns take 1 unit of weight on mobile
and expand to 4 units on large screens.
-->
<div layout="Grid.col({ sm: 1, lg: 4 }, 10, { sm: 1, lg: 4 })">
<div>Side Gutter</div>
<div>Main Content (10 Units)</div>
<div>Side Gutter</div>
</div>
<Layout
layout={Grid.col(
{ sm: 1, lg: 4 },
10,
{ sm: 1, lg: 4 }
)}
>
<div>Side Gutter</div>
<div>Main Content</div>
<div>Side Gutter</div>
</Layout>
Visual Demo: Resize your browser window to see the blue content area stay stable while the gray gutters expand.
Tip: Because the weights are proportional, the engine automatically calculates the percentages. You don't need to worry about the total sum; just focus on the ratio between parts.
Layout Modification
With native execution in v1.2.0, layout modification becomes intuitive and math-driven. You can define column sizes using fractions, decimals, and standard CSS units directly. This allows for faster, cleaner, and more flexible layout adjustments.
1. Native Math (Fractions)
Instead of calculating percentages manually, simply type fractions. This allows you to define any number of columns, beyond the usual 12 or 24.
<div layout="Grid.col(1/3, 1/3, 1/3)">
<Layout layout={Grid.col(1/3, 1/3, 1/3)}>
2. CSS Units (Fixed Sizes)
You can pass strings to use standard CSS units like px, rem, or %. These act as fixed tracks.
<div layout="Grid.col('150px', 1, '150px')">
<Layout layout={Grid.col('150px', 1, '150px')}>
3. Decimals
The engine treats 0.5 exactly the same as 50 or 1/2. It calculates the ratio based on the total sum of siblings.
<div layout="Grid.col(0.7, 0.3)">
<Layout layout={Grid.col(0.7, 0.3)}>
4. Variables (Golden Ratio)
The engine provides built-in variables: lg (61.8) and sm (38.2).
<div layout="Grid.col(lg, sm)">
<Layout layout={Grid.col(lg, sm)}>
5. Mixed Units & Recursion
You can mix fixed CSS strings, auto, and ratios. You can also apply recursion directly to string units (e.g. splitting a '200px' column into rows).
<div layout="Grid.col(
('200px').row(1,1), // Fixed col split into 2 rows
'auto',
'auto'
)">
<Layout layout={Grid.col(
('200px').row(1,1),
'auto',
'auto'
)}>
Customisation
External Styling (Classes & IDs)
While .props() is great for quick adjustments, you often want to control the container's dimensions using standard CSS classes or IDs. This keeps your layout logic separate from your sizing logic.
The framework respects all standard class names and IDs applied to the element.
<style>
/* Standard CSS */
.hero-container {
height: 300px;
width: 80%;
margin: 0 auto; /* Center it */
border: 2px solid red;
}
</style>
<!-- Apply class here -->
<div class="hero-container" layout="Grid.col(50, 50)">
<div>Left</div>
<div>Right</div>
</div>
import './App.css'; // Contains .hero-container styles
export default function App() {
return (
<Layout
className="hero-container"
layout={Grid.col(50, 50)}
>
<div>Left</div>
<div>Right</div>
</Layout>
);
}
(The container below is restricted to 80% width and centered via CSS)
Easy Recursive Loops
To make 12 equal columns manually would be tedious. Because v1.2.0 uses native JS, you can generate arrays dynamically!
<script> window.twelveCols = Array(12).fill(1); </script> <div layout="Grid.col(...twelveCols)"> <!-- 12 Divs --> </div>
Utilities Methods
When using Grid().row() and Grid().col() recursively, layouts may not align as expected because of the declarative syntax. To handle these cases, Rowscolumns provides 4 utility methods that let you style, offset, or span grid items without breaking the layout. These methods work by applying CSS directly through JavaScript.
Styling Methods
Styling methods are only for styling the container it uses CSS property. If inline styling is written it will be overridden by the these styling methods.
.props({ styles })
Apply CSS properties to the grid container (like gap, padding, margins).
Grid.col(50, 50).props({ gap: '20px', padding: '10px' })
Grid.col(50, 50).props({ gap: '20px', padding: '10px' })
.childProps({ styles }, [indices])
Apply CSS properties to specific children. Indices are 1-based.
Grid.col(33, 33, 33).childProps({ background: 'turquoise' }, [2])
Grid.col(33, 33, 33).childProps({ background: 'turquoise' }, [2])
Tip : You can select multiple children always. .childProps({ background: 'turquoise' }, [1, 3]) This will apply to 1st and 3rd children.
Markup Methods
Markup methods affect the structure of the grid, rather than just its appearance. They modify how grid slots are created and positioned.
.offset([indices])
Creates "Ghost" slots. Useful for creating gaps. In this demo, we skip the middle slot (Index 2), forcing the 2nd Box to jump to the 3rd slot.
<Layout layout={Grid.col(33, 33, 33).offset([2])}>
<div>1</div>
<div>2</div>
</Layout>
Tip : You can also use it directly on the element Grid.col(33, (33).offset(), 33)
.span({ direction }, [indices])
Expands an item across multiple tracks (Spanning). Directions: top (top), right (right), bottom (bottom), left (left).
Examples:
.span({right:1}, [1]) spans the first child to the right;
.span({left:1}, [2]) spans the second child to the left;
.span({bottom:1}, [1, 2])spans first and second child downward;
.span({top:1}, [2]) upward by 2.
The second parameter targets child indices (1-based), so [1] is the first child, [2] the second, and multiple can be set like [1,3].
<Layout layout={Grid.col(33, 33, 33).offset([2]).span({right:1}, [1])}>
<div>1</div>
<div>2</div>
</Layout>
LAYOUTS
Advanced Layout Patterns
The "Holy Grail" (12-Column Style)
Instead of arbitrary percentages, you can use the classic 12-column system fractions. Here, we create a layout with a Header, a 3-column Sidebar, a 9-column Content area, and a Footer. Where Footer and Header are taken 1-rows and Body 2-rows. This makes a perfect two dimensional
Grid.row( 1/4, // Header 1 of 4 (2/4).col(3/12, 5/12), // Body 2 of 4 with columns: Sidebar (3/12) + Content (5/12) 1/4 // Footer 1 of 4 )
Deep Recursion (Mondrian Style)
Grid.col(50, (50).row(50, (50).col(50, 50)))
Golden Ratio
You can create a golden-ratio layout (Fibonacci spiral) using the built-in lg and sm variables (lg = 61.8, sm = 38.2).
Each split rotates the layout, and the smaller section becomes the container for the next split, producing a centered spiral:
Grid.col(
lg,
sm.row(
lg,
sm.col(
sm.row(
sm.col(
lg,
sm.row(
lg,
sm.col(
sm.row(
sm.col(lg, sm)
, lg)
, lg)
)
, lg)
, lg)
, lg)
)
)
For a more visual effect, you can also add rounded corners to the children to create the spiral curve:
Complex Symmetry
Creating a symmetrical 23-element layout in standard HTML requires complex nesting or manual percentage calculations. With Rowscolumns, you just mirror the layout string.
Comparison: In standard CSS, you would need to calculate width: 4.34%, width: 8.69%, etc., or use complex Flexbox nesting. Here, it is one line of logic.
Grid.col( (10).row(1,1,1,1,1,1,1,1), // Left Wing (8 rows) (20).row(1,1,1), // Inner Left (3 rows) 40, // Center (1 big col) (20).row(1,1,1), // Inner Right (3 rows) (10).row(1,1,1,1,1,1,1,1) // Right Wing (8 rows) )
Massive Rhythm (20 Columns)
Handling 20+ columns in native CSS Grid often involves tedious repeat() syntax or manual fractional math. Rowscolumns handles the math for any number of elements instantly.
This example generates 20 columns that progressively grow larger, creating a visual rhythm.
Grid.col(1, 2, 3, 4, 5, 6, 7 ... 20)
Asymmetrical Balance
Standard grids often feel rigid. By using a 6-column base and the .span() method, elements can cross the center axis, creating dynamic, asymmetrical balance.
This layout uses .offset() to create negative space and .span() to bridge columns.
Grid.col(
(1).row(1,1,1,3).span({right:1},[3,4]),
(1).row(2,1,3).span({right:1},[1]).offset([2,3]),
(1).row(2,2,1,1).offset([1]).span({right:1},[1]),
(1).row(1,1,2,2).offset([3]).span({right:1},[3]),
(1).row(3,1,2).offset([3]).span({right:1},[2,1]),
(1).row(3,1,1,1).offset([1,2])
).props({gap:'5px'})
Or more simplified.
Grid.col(
(1).row(1,1,1,3),
(1).row(2,1,3),
(1).row(2,2,1,1),
(1).row(1,1,2,2),
(1).row(3,1,2),
(1).row(3,1,1,1)
)
.span({right:1},[3,4,5,6,11,12,13])
.offset([6,7,8,14,18,19,20])
DEVELOPMENT
Responsive Design
Rowscolumns v1.6.X introduces Inline Responsive Objects. While you can still use multiple attributes, you can now define full responsiveness within a single method using the { breakpoint: value } syntax.
| Attribute / Key | Breakpoint | Device |
|---|---|---|
xs / layout | 0px | Mobile (Default) |
sm / layout-sm | ≥ 576px | Large Phones |
md / layout-md | ≥ 768px | Tablets |
lg / layout-lg | ≥ 992px | Laptops |
xl / layout-xl | ≥ 1200px | Desktops |
The 'none' Keyword
The 'none' keyword is a special layout value. It doesn't just hide the element; it collapses the grid track entirely so that gaps and margins disappear, making surrounding elements slide into place perfectly.
Real World Example: The Navbar
Let's build a responsive navigation bar using the new inline syntax:
- Mobile: Logo (Left), Menu (Right). The Search Bar is hidden and its space is collapsed.
- Desktop: Logo, a large Search Bar in the middle, and the Menu.
<!--
The 2nd column uses an object:
- sm: 'none' (Hidden, no space taken)
- md: 1 (Takes available space on tablets+)
-->
<div layout="Grid.col(auto, { sm: 'none', md: 1 }, auto).props({ gap: '15px' })">
<div>Logo</div>
<input type="text" placeholder="Search..." />
<button>Menu</button>
</div>
<Layout
// Unified logic in one attribute
layout={Grid.col(
'auto',
{ sm: 'none', md: 1 },
'auto'
).props({ gap: '15px' })}
>
<div>Logo</div>
<input type="text" placeholder="Search..." />
<button>Menu</button>
</Layout>
Resize your browser window to see the Search Bar appear and disappear without leaving "ghost" gaps!
Pro Tip: Responsive Multi-Weights
You can even change the relative weights of columns dynamically:
Grid.col({ sm: 1, md: 5, lg: 10 })
This single column will take 1 unit of space on mobile, 5 on tablets, and 10 on large screens.
Multi-Framework Support
Rowscolumns provides dedicated wrappers for the modern web ecosystem. The logic remains the same, but the syntax adapts to your framework.
npx create-vite@latest my-rc-website cd my-rc-website npm install rowscolumns
1. Setup
import { Layout, Grid, lg, sm } from 'rowscolumns/react';
2. Responsive Layout
Pass objects directly to props. Note that we keep the dash syntax for consistency.
export const App = () => {
return (
<Layout
// Mobile (Default)
layout={Grid.col(100)}
// Tablet (768px+)
layout-md={Grid.col(50, 50)}
// Desktop (992px+)
layout-lg={Grid.col(lg, sm)}
>
<div>Box 1</div>
<div>Box 2</div>
</Layout>
);
};
1. Setup
<script setup>
import { Layout, Grid, lg, sm } from 'rowscolumns/vue';
</script>
2. Responsive Layout
Use standard Vue binding : to pass the layout objects.
<template>
<Layout
:layout="Grid.col(100)"
:layout-md="Grid.col(50, 50)"
:layout-lg="Grid.col(lg, sm)"
>
<div>Box 1</div>
<div>Box 2</div>
</Layout>
</template>
1. Setup (Component)
Import the standalone component and define your grids in the class.
import { Component } from '@angular/core';
import { RowscolumnsComponent } from 'rowscolumns/angular';
import { Grid, lg, sm } from 'rowscolumns';
@Component({
standalone: true,
imports: [RowscolumnsComponent],
templateUrl: './app.component.html'
})
export class AppComponent {
mobile = Grid.col(100);
tablet = Grid.col(50, 50);
desktop = Grid.col(lg, sm);
}
2. Template (HTML)
Bind the class properties to the component inputs.
<rc-layout [layout]="mobile" [layout-md]="tablet" [layout-lg]="desktop" > <div>Box 1</div> <div>Box 2</div> </rc-layout>
3. Run
npm run dev
Now visit http://localhost:5173/
Layout vs. Components
Rowscolumns is strictly a Layout Engine. It decides where elements go, not what they look like.
This means it works perfectly with external CSS, CSS Modules, or UI Libraries (Bootstrap, Material, Tailwind).
External CSS / Modules
You define the structure in the attribute, and the look in your CSS file.
<!-- CSS -->
<style>
.card { background: white; shadow: 0 4px 10px rgba(0,0,0,0.1); }
.btn { background: blue; color: white; }
</style>
<!-- HTML -->
<div layout="Grid.col(50, 50)">
<div class="card">Product Info</div>
<button class="btn">Buy Now</button>
</div>
Using with UI Kits (Bootstrap / Tailwind)
Because Rowscolumns doesn't pollute the children with layout classes, you can drop in components from other frameworks directly.
<div layout="Grid.col(33, 33, 33).props({gap:'20px'})">
<!-- Tailwind Card -->
<div class="bg-white rounded-lg shadow-lg p-6">
Tailwind Card
</div>
<!-- Bootstrap Button -->
<button class="btn btn-primary btn-lg">
Bootstrap Button
</button>
<!-- Material UI style -->
<div class="mui-paper elevation-3">
Material Component
</div>
</div>
OTHERS
Support Rows & Columns
If you find Rows & Columns useful and want to support its development, your contribution helps add new features, and improve the framework.
Global Support
- GitHub Sponsors – one-time or recurring contributions
- Buy Me a Coffee – micro-donations and subscriptions
Support from India
- UPI / Google Pay / PhonePe / Paytm: abhimm5@upi
Even if you cannot donate, sharing the project, starring it on GitHub, or contributing feedback helps a lot!
About
Rowscolumns was created to bridge the gap between Design Tools (which think in groups, frames, and auto-layout) and CSS Code (which thinks in classes and flow).
By moving layout logic into a recursive mathematical structure, we keep the DOM clean and the styles separated.
License
Rowscolumns is open-source software licensed under the MIT License. You are free to use it in personal and commercial projects.
Community & Contribution
Built by Abhimm5. Contributions are welcome on GitHub.