https://github.com/cuire/svelte-grid-extended
A draggable and resizable grid layout, for Svelte
https://github.com/cuire/svelte-grid-extended
drag dragable grid resizable resize svelte
Last synced: 8 months ago
JSON representation
A draggable and resizable grid layout, for Svelte
- Host: GitHub
- URL: https://github.com/cuire/svelte-grid-extended
- Owner: cuire
- License: mit
- Created: 2022-09-18T16:31:36.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2024-11-25T16:03:53.000Z (over 1 year ago)
- Last Synced: 2025-09-30T12:53:41.677Z (8 months ago)
- Topics: drag, dragable, grid, resizable, resize, svelte
- Language: Svelte
- Homepage: https://svelte-grid-extended.vercel.app
- Size: 1.81 MB
- Stars: 112
- Watchers: 6
- Forks: 15
- Open Issues: 25
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# svelte-grid-extended 🍾
[](https://badge.fury.io/js/svelte-grid-extended)

## Description
Svelte-Grid-Extended is a draggable, resizable ~~and responsive~~ grid layout. The package is created as extended verison of [svelte-grid](https://github.com/vaheqelyan/svelte-grid).
## Installation
With NPM:
```sh
npm install svelte-grid-extended
```
With Yarn:
```shPackage currently in alpha, please consider that it **will** be changed in the future
yarn add svelte-grid-extended
```
With pnpm:
```sh
pnpm add svelte-grid-extended
```
### Table of Contents
- [Description](#description)
- [Installation](#installation)
- [Table of Contents](#table-of-contents)
- [Usage](#usage)
- [Basic](#basic)
- [Static grid](#static-grid)
- [Grid without bounds](#grid-without-bounds)
- [Styling](#styling)
- [Disable interactions](#disable-interactions)
- [Collision Behavior](#collision-behavior)
- [None](#none)
- [Push](#push)
- [Compress](#compress)
- [Custom move/resize handle](#custom-moveresize-handle)
- [Two way binding](#two-way-binding)
- [API Documentation](#api-documentation)
- [Grid props](#grid-props)
- [GridItem props](#griditem-props)
- [Style related props:](#style-related-props)
- [Events](#events)
- [Grid Controller](#grid-controller)
- [Methods](#methods)
- [getFirstAvailablePosition(w, h)](#getfirstavailablepositionw-h)
- [Example](#example)
- [📜 License](#-license)
## Usage
### Basic
✨ [repl](https://svelte.dev/repl/effd88614c0c4372864ebeb582415a21?version=4.1.1)
```svelte
import Grid, { GridItem } from 'svelte-grid-extended';
Hey
Hoy
```
### Static grid
When `cols` or `rows` and `itemsSize` are set, grid becomes static and ignores the size of the container.
It can be set to both dimensions or just one.
Both:
✨ [repl](https://svelte.dev/repl/7d431c0884d343529e5e98fcbe74afbd?version=4.1.1)
```svelte
import Grid, { GridItem } from 'svelte-grid-extended';
const itemSize = { width: 100, height: 40 };
Hey
Hoy
```
Only rows:
✨ [repl](https://svelte.dev/repl/53994707c9f84d2cad2f9eac5a9f9ea6?version=4.1.1)
```svelte
import Grid, { GridItem } from 'svelte-grid-extended';
const itemSize = { height: 40 };
Hey
Hoy
```
### Grid without bounds
When `cols` or/and `rows` set to 0, grid grows infinitly. The grid container adapts its width and height to fit all elements.
It can be set to both dimensions or just one.
✨ [repl](https://svelte.dev/repl/ade95bbc3a7445518df6a51c3fd9be2e?version=4.1.1)
```svelte
import Grid, { GridItem } from 'svelte-grid-extended';
const itemSize = { width: 100, height: 40 };
Hey
Hoy
```
### Styling
Grid can be styled with classes passed to various props. Check [Style related props](#style-related-props) section for more info.
✨ [repl](https://svelte.dev/repl/97243bc1472d42ff944e47c30b72d73d?version=4.1.1)
```svelte
import Grid, { GridItem } from 'svelte-grid-extended';
{item.id}
:global(.grid-container) {
opacity: 0.7;
}
:global(.grid-item) {
transition:
width 4s,
height 4s;
transition:
transform 4s,
opacity 4s;
}
:global(.grid-item-active) {
opacity: 0.1;
}
/* tailwind classes */
:global(.bg-red-500) {
background-color: rgb(202, 33, 33);
}
:global(.rounded) {
border-radius: 0.25rem;
}
```
### Disable interactions
To disable interactions, set `readOnly` prop to `true`. Or set `movable` and/or `resizable` to `false` on specific item.
Read Only grid: ✨ [repl](https://svelte.dev/repl/e7183ff3136c47fe94fcd5398573aef5?version=4.1.1)
```svelte
import Grid, { GridItem } from 'svelte-grid-extended';
Hey
Hoy
```
Make item non-interactive: ✨ [repl](https://svelte.dev/repl/50f1acb8be5b426896cb6d9b6c10e9f8?version=4.1.1)
```svelte
import Grid, { GridItem } from 'svelte-grid-extended';
Hey
Hoy
```
### Collision Behavior
The `collision` prop controls how the grid handles collisions. There are three available options: `none`, `push`, and `compress`.
#### None
Setting `collision` prop to `none` will ignore any collisions. This is the default behavior.
✨ [repl](https://svelte.dev/repl/c549a05c30b84793b2bab156f49bedd3?version=4.1.1)
```svelte
import Grid, { GridItem } from 'svelte-grid-extended';
const items = [
{ id: '0', x: 0, y: 0, w: 2, h: 5 },
{ id: '1', x: 2, y: 2, w: 2, h: 2 },
{ id: '2', x: 2, y: 0, w: 1, h: 2 },
{ id: '3', x: 3, y: 0, w: 2, h: 2 },
{ id: '4', x: 4, y: 2, w: 1, h: 3 },
{ id: '5', x: 8, y: 0, w: 2, h: 8 }
];
const itemSize = { height: 40 };
{#each items as item}
{item.id}
{/each}
```
#### Push
Setting `collision` prop to `push` will cause grid items to move to the first available space when colliding. The grid will grow vertically as needed to accommodate all items.
✨ [repl](https://svelte.dev/repl/36abb5e5be6f4b0ebe637b2676ccf606?version=4.1.1)
```svelte
import Grid, { GridItem } from 'svelte-grid-extended';
const items = [
{ id: '0', x: 0, y: 0, w: 2, h: 5 },
{ id: '1', x: 2, y: 2, w: 2, h: 2 },
{ id: '2', x: 2, y: 0, w: 1, h: 2 },
{ id: '3', x: 3, y: 0, w: 2, h: 2 },
{ id: '4', x: 4, y: 2, w: 1, h: 3 },
{ id: '5', x: 8, y: 0, w: 2, h: 8 }
];
const itemSize = { height: 40 };
{#each items as item}
{item.id}
{/each}
```
#### Compress
Setting `collision` prop to `compress` will compress items vertically towards the top into any available space when colliding. The grid will grow vertically as needed to accommodate all items.
✨ [repl](https://svelte.dev/repl/86cff54f2efa437285c3245ecb713702?version=4.1.1)
```svelte
import Grid, { GridItem } from 'svelte-grid-extended';
const items = [
{ id: '0', x: 0, y: 0, w: 2, h: 5 },
{ id: '1', x: 2, y: 2, w: 2, h: 2 },
{ id: '2', x: 2, y: 0, w: 1, h: 2 },
{ id: '3', x: 3, y: 0, w: 2, h: 2 },
{ id: '4', x: 4, y: 2, w: 1, h: 3 },
{ id: '5', x: 8, y: 0, w: 2, h: 8 }
];
const itemSize = { height: 40 };
{#each items as item}
{item.id}
{/each}
```
> ⚠️ Setting `collision` to `push` or `compress` will set `rows` to `0` so `ItemSize.height` must be setted.
### Custom move/resize handle
✨ [repl](https://svelte.dev/repl/5f9dbbd845cc40f6a222734856fc9b1d?version=4.1.1)
```svelte
import Grid, { GridItem } from 'svelte-grid-extended';
MOVE
Resize
```
### Two way binding
✨ [repl](https://svelte.dev/repl/ef5d5716505642b7a9212c3d0c7b6803?version=4.1.1)
```svelte
import Grid, { GridItem } from 'svelte-grid-extended';
let items = [
{ x: 6, y: 0, w: 2, h: 2, data: { text: '🎅' } },
{ x: 6, y: 2, w: 2, h: 2, data: { text: '🤶' } }
];
const itemsBackup = structuredClone(items);
function resetGrid() {
items = structuredClone(itemsBackup);
}
RESET
{#each items as item}
{item.data.text}
{/each}
```
## API Documentation
### Grid props
| prop | description | type | default |
| ------------ | ---------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | ------- |
| cols | Grid columns count. If set to 0, grid will grow infinitly. Must be >= 0. | number | 0 |
| rows | Grid rows count. If set to 0, grid will grow infinitly. Must be >= 0. | number | 0 |
| itemSize | Size of the grid item. If not set, grid will calculate it based on container size. | { width?: number, height?: number } | {} |
| gap | Gap between grid items. | number | 10 |
| bounds | Should grid items be bounded by the grid container. | boolean | false |
| readonly | If true disables interaction with grid items. | boolean | false |
| collision | Collision behavior of grid items. [About](#collision-behavior) | none \| push \| compress | none |
| autoCompress | Auto compress the grid items when programmatically changing grid items. Only works with 'compress' collision strategy. | boolean | true |
> ⚠️ if `cols` or/and `rows` are set to 0, `itemSize.width` or/and `itemSize.height` must be setted.
> ⚠️ Setting `collision` to `push` or `compress` will set `rows` to `0` so `ItemSize.height` must be setted.
### GridItem props
| prop | description | type | default |
| --------- | -------------------------------------------------------------------------------------------------- | ------------------------------------- | -------------- |
| id | Unique id of the item. Used to compare items during collision tests | string | uuid.v4 |
| x | X position of the item in grid units. | number | required |
| y | Y position of the item in grid units. | number | required |
| w | Width of the item in grid units. | number | 1 |
| h | Height of the item in grid units. | number | 1 |
| min | Minimum size of the item in Grid Units. | { w: number, h: number } | { w: 1, h: 1 } |
| max | Maximum size of the item in Grid Units. If not provided, the item will be able to grow infinitely. | { w: number, h: number } \| undefined | undefined |
| movable | If true, item can be moved by user. | boolean | true |
| resizable | If true, item can be resized by user. | boolean | true |
### Style related props:
Component can be styled with css framework of your choice, global classes or `style` prop. To do so, you can use the following props:
- `` - class name for grid container.
- `` - inline style for grid container.
- `` - class name for grid item.
- `` - class name that applies when item is currently being dragged or resized. By default, it is used to make active grid item transparent.
- `` - class name for preview where item will be placed after interaction.
- `` - class name for item's resize handle.
- `` - inline style for grid item.
To understand how to use these props, look at `` component simplified structure.
> 📄 `active` is variable that indicates if grid item is currently being dragged or resized:
```svelte
{#if active}
{/if}
```
## Events
Grid emits the following events:
| event name | description | payload |
| ---------- | ------------------------------------ | ------------------ |
| change | Emitted when grid items are changed. | {item: LayoutItem} |
```svelte
import Grid, { GridItem, type LayoutChangeDetail } from 'svelte-grid-extended';
function logItem(event: CustomEvent<LayoutChangeDetail>) {
console.log(event.detail.item);
}
Hey
Hoy
```
## Grid Controller
The Grid Controller provides utility functions that allow for more advanced control and customization of the grid. It's obtained from the Grid component using the `bind:controller` attribute, offering a way to interact with the grid in a programmatic and flexible manner.
### Methods
#### getFirstAvailablePosition(w, h)
Finds the first available position within the grid that can accommodate an item of the specified width (w) and height (h). This method is useful when dynamically adding new items to the grid, ensuring that they fit into the first available space that can hold them.
**Parameters:**
- `w` (number): Width of the item.
- `h` (number): Height of the item.
**Returns:**
- An object containing the `x` and `y` coordinates of the first available position, or `null` if no position is available.
##### Example
✨ [repl](https://svelte.dev/repl/6af014e1f754458dbc15c1823dbdca3c?version=4.1.2)
```svelte
import Grid, { GridItem, type GridController } from 'svelte-grid-extended';
let items = [
{ id: '1', x: 0, y: 0, w: 2, h: 5 },
{ id: '2', x: 2, y: 2, w: 2, h: 2 }
];
let gridController: GridController;
function addNewItem() {
const w = Math.floor(Math.random() * 2) + 1;
const h = Math.floor(Math.random() * 5) + 1;
const newPosition = gridController.getFirstAvailablePosition(w, h);
items = newPosition
? [...items, { id: crypto.randomUUID(), x: newPosition.x, y: newPosition.y, w, h }]
: items;
}
const itemSize = { height: 40 };
Add New Item
{#each items as { id, x, y, w, h } (id)}
{id}
{/each}
```
#### compress()
Compresses all items vertically towards the top into any available space.
##### Example
✨ [repl](https://svelte.dev/repl/79bcc70f11944d9e9b03970de731b3e2?version=4.2.11)
```svelte
import Grid, { GridItem, type GridController } from 'svelte-grid-extended';
let items = [
{ id: '1', x: 0, y: 0, w: 2, h: 5 },
{ id: '2', x: 2, y: 2, w: 2, h: 2 }
];
let gridController: GridController;
function compressItems() {
gridController.compress();
}
const itemSize = { height: 40 };
Compress Items
{#each items as item (item.id)}
{item.id.slice(0, 5)}
{/each}
```
## 📜 License
MIT