Package Exports
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (dynamic-gridline) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme

Dynamic Gridline
A draggable and zoomable grid system for placing items.
Report Bug
·
Request Feature
Table of Contents
About The Project
Built With
Getting Started
Prerequisites
# npm
npm install motion @radix-ui/react-slider
# yarn
yarn add motion @radix-ui/react-slider
# pnpm
pnpm add motion @radix-ui/react-slider
# bun
bun install motion @radix-ui/react-slider
Installation
# npm
npm install dynamic-gridline
# yarn
yarn add dynamic-gridline
# pnpm
pnpm add dynamic-gridline
# bun
bun install dynamic-gridline
Usage
Basic Setup
Import the components and start building your interactive grid:
import { Grid, GridItem } from 'dynamic-gridline'
function App() {
return (
<div style={{ width: '100vw', height: '100vh' }}>
<Grid>
<GridItem x={100} y={100}>
<div>Your content here</div>
</GridItem>
</Grid>
</div>
)
}
Core Components
Grid Component
The Grid
component is the main container that provides the interactive canvas with pan, zoom, and grid functionality.
import { Grid } from 'dynamic-gridline'
function InteractiveCanvas() {
return (
<Grid
config={{
width: 10000,
height: 8000,
gridCellSize: 50,
minZoom: 0.1,
maxZoom: 2,
gridColor: '#e0e0e0',
}}
>
{/* Your grid items go here */}
</Grid>
)
}
GridItem Component
The GridItem
component positions content within the grid coordinate system.
import { Grid, GridItem } from 'dynamic-gridline'
function ItemPlacement() {
return (
<Grid>
<GridItem x={0} y={0}>
<div style={{ background: 'red', text: 'white', padding: '10px' }}>(0,0)</div>
</GridItem>
<GridItem x={200} y={150}>
<div style={{ background: 'blue', text: 'white', padding: '10px' }}>(200,150)</div>
</GridItem>
<GridItem x={-150} y={-50}>
<div style={{ background: 'green', text: 'white', padding: '10px' }}>(-150, -50)</div>
</GridItem>
</Grid>
)
}
Advanced Features
Disable Scale for Grid Items
Control whether items scale with zoom using the disableScale
property:
function ScalingDemo() {
return (
<Grid config={{ minZoom: 0.5, maxZoom: 2 }}>
{/* This circle will scale with zoom */}
<GridItem x={-100} y={0} disableScale={false}>
<div
style={{
width: 120,
height: 120,
color: 'white',
borderRadius: '50%',
background: 'blue',
}}
></div>
</GridItem>
{/* This circle maintains constant size */}
<GridItem x={100} y={0} disableScale={true}>
<div
style={{
width: 120,
height: 120,
color: 'white',
borderRadius: '50%',
background: 'red',
}}
></div>
</GridItem>
</Grid>
)
}
Fixed Z-Index Control
Control layering of grid items with fixedZIndex
:
function LayeringDemo() {
return (
<Grid>
<GridItem x={-50} y={-50} fixedZIndex={1}>
<div
style={{
width: 100,
height: 100,
background: 'rgba(255,0,0,0.7)',
color: 'white',
}}
>
Behind (z-index: 1)
</div>
</GridItem>
<GridItem x={0} y={0} fixedZIndex={10}>
<div
style={{
width: 100,
height: 100,
background: 'rgba(0,0,255,0.7)',
color: 'white',
}}
>
In Front (z-index: 10)
</div>
</GridItem>
</Grid>
)
}
Interaction Features
Click Event Handlers
Handle fast clicks and hold clicks on the grid:
function ClickHandling() {
const handleFastClick = ({ x, y }: { x: number; y: number }) => {
console.log('Fast click at:', x, y)
// Add logic for quick interactions
}
const handleHoldClick = ({ x, y }: { x: number; y: number }) => {
console.log('Hold click at:', x, y)
// Add logic for context menus or long-press actions
}
return (
<Grid
config={{
onFastClick: handleFastClick,
onHoldClick: handleHoldClick,
}}
>
<GridItem x={0} y={0}>
<div>Try clicking and holding on the grid!</div>
</GridItem>
</Grid>
)
}
Mouse Movement Tracking
Track mouse position within the grid coordinate system:
function MouseTracking() {
const [mousePos, setMousePos] = useState({ x: 0, y: 0 })
const handleMouseMove = ({ x, y }: { x: number; y: number }) => {
setMousePos({ x, y })
}
return (
<div style={{ width: '100vw', height: '100vh' }}>
<p style={{ position: 'absolute', top: 0, left: 0 }}>
Mouse position: ({mousePos.x.toFixed(2)}, {mousePos.y.toFixed(2)})
</p>
<Grid config={{ onMouseMove: handleMouseMove }}>
<GridItem x={mousePos.x} y={mousePos.y}>
<div
style={{
width: 10,
height: 10,
background: 'red',
borderRadius: '50%',
}}
/>
</GridItem>
</Grid>
</div>
)
}
Navigation Controls
Keyboard Navigation
Navigate the grid using arrow keys:
function KeyboardNavigation() {
return (
<Grid
config={{
panStep: 50, // Pixels to move per arrow key press
keyDisabled: false, // Enable keyboard controls
}}
>
<GridItem x={0} y={0}>
<div>Use arrow keys to pan around!</div>
</GridItem>
</Grid>
)
}
Zoom Controls
Built-in zoom slider and wheel zoom functionality:
function ZoomDemo() {
return (
<Grid
config={{
minZoom: 0.25,
maxZoom: 4,
zoomSteps: 50,
wheelDisabled: false, // Enable mouse wheel zoom
}}
>
<GridItem x={0} y={0}>
<div>Use mouse wheel or slider to zoom!</div>
</GridItem>
</Grid>
)
}
Customization Options
Custom Grid Appearance
Customize the grid's visual appearance:
function CustomStyling() {
return (
<Grid
config={{
gridBackground: '#1b2845',
gridColor: '#4f88cb', // Custom grid line color
gridCellSize: 30, // Smaller grid cells
}}
>
<GridItem x={0} y={0}>
<div style={{ color: 'white' }}>Custom styled grid!</div>
</GridItem>
</Grid>
)
}
Custom Zoom Slider
Replace the default zoom slider with your own component:
function CustomZoomSlider() {
const customSlider = (sliderProps: SliderProps) => (
<div
style={{
position: 'absolute',
top: 20,
right: 20,
background: 'white',
padding: '10px',
borderRadius: '8px',
boxShadow: '0 2px 10px rgba(0,0,0,0.1)',
}}
>
<label>Zoom: {sliderProps.zoomValue.toFixed(2)}x</label>
<input
type="range"
min={Math.log10(sliderProps.minZoom)}
max={Math.log10(sliderProps.maxZoom)}
step={
(Math.log10(sliderProps.maxZoom) - Math.log10(sliderProps.minZoom)) /
(sliderProps.zoomSteps - 1)
}
value={Math.log10(sliderProps.zoomValue)}
onChange={(e) => sliderProps.handleZoom(10 ** parseFloat(e.target.value))}
/>
</div>
)
return (
<Grid config={{ customZoomSlider: customSlider }}>
<GridItem x={0} y={0}>
<div>Custom zoom control!</div>
</GridItem>
</Grid>
)
}
Disabling Features
Selective Feature Disabling
Disable specific interactions while keeping others active:
function SelectiveDisabling() {
return (
<div
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: '100vw',
height: '100vh',
gap: '20px',
}}
>
<div style={{ width: '30vw', aspectRatio: '1/1' }}>
<Grid config={{ panDisabled: true, wheelDisabled: false }}>
<GridItem x={0} y={0}>
<div>Zoom only</div>
</GridItem>
</Grid>
</div>
{/* Wheel zoom disabled, pan still works */}
<div style={{ width: '30vw', aspectRatio: '1/1' }}>
<Grid config={{ panDisabled: false, wheelDisabled: true }}>
<GridItem x={0} y={0}>
<div>Pan only</div>
</GridItem>
</Grid>
</div>
{/* Everything disabled */}
<div style={{ width: '30vw', aspectRatio: '1/1' }}>
<Grid config={{ disabled: true }}>
<GridItem x={0} y={0}>
<div>Static view</div>
</GridItem>
</Grid>
</div>
</div>
)
}
Grid Reference and Imperative Controls
Access grid methods using a ref:
import { useRef } from 'react'
import { Grid, GridRef } from 'dynamic-gridline'
function GridWithRef() {
const gridRef = useRef<GridRef>(null)
const focusGrid = () => {
gridRef.current?.focusGrid()
}
return (
<div>
<button onClick={focusGrid}>Focus Grid (for keyboard controls)</button>
<Grid ref={gridRef}>
<GridItem x={0} y={0}>
<div>Grid with ref access</div>
</GridItem>
</Grid>
</div>
)
}
Configuration Reference
The Grid
component accepts a config
prop with the following options:
Property | Type | Default | Description |
---|---|---|---|
width |
number |
window.innerWidth * 10 |
Total width of the grid canvas in pixels |
height |
number |
window.innerHeight * 10 |
Total height of the grid canvas in pixels |
gridCellSize |
number |
20 |
Size of each grid cell in pixels |
gridBackground |
string |
'transparent' |
Background color of the grid container |
gridColor |
string |
'oklch(70.7% 0.022 261.325)' |
Color of the grid lines |
minZoom |
number |
0.1 |
Minimum zoom level (0.1 = 10%) |
maxZoom |
number |
1 |
Maximum zoom level (1 = 100%) |
zoomSteps |
number |
100 |
Number of steps in the zoom slider |
panStep |
number |
10 |
Pixels to move when using keyboard navigation |
disabled |
boolean |
false |
Disable all interactions (pan, zoom, keyboard) |
panDisabled |
boolean |
false |
Disable panning (mouse drag and touch) |
wheelDisabled |
boolean |
false |
Disable mouse wheel zooming |
keyDisabled |
boolean |
false |
Disable keyboard navigation |
customZoomSlider |
((props: SliderProps) => ReactNode) | null |
null |
Custom zoom slider component |
onFastClick |
({ x, y }: { x: number; y: number }) => void |
undefined |
Callback for quick clicks on the grid |
onHoldClick |
({ x, y }: { x: number; y: number }) => void |
undefined |
Callback for long presses on the grid |
onMouseMove |
({ x, y }: { x: number; y: number }) => void |
undefined |
Callback for mouse movement over the grid |
GridItem Properties
Property | Type | Default | Description |
---|---|---|---|
x |
number |
Required | X coordinate in grid space |
y |
number |
Required | Y coordinate in grid space |
disableScale |
boolean |
false |
Prevent item from scaling with zoom |
fixedZIndex |
number |
undefined |
Fixed z-index for layering control |
children |
ReactNode |
Required | Content to render in the grid item |
Contributing
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature
) - Commit your Changes (
git commit -m 'Add some AmazingFeature'
) - Push to the Branch (
git push origin feature/AmazingFeature
) - Open a Pull Request
Top contributors:
License
Distributed under the MIT License. See LICENSE
for more information.
Contact
Omar Hassan - @omar_elfat76510 - elfatairy@omarhassan.net
Project Link: https://github.com/elfatairy/dynamic-gridline
Portfolio: https://omarhassan.net