Skip to content

FreeformGrid

A fixed raster of cells to place items on — the basis for desktop-style icon grids, where every item sits in a cell instead of flowing in a list.

FreeformGrid draws the raster and tells you which cell the cursor is over. It does not move anything by itself: you decide where items land, and resolveGridDrop does that maths for you if you want it.

Usage

vue
<FreeformGrid ref="gridRef" :columns="6" :rows="4" gap="8px">
  <template #cell="{ cell, isHovered }">
    <div class="rounded border-2 border-dashed" :class="isHovered && 'border-blue-500'" />
  </template>

  <FreeformItem
    v-for="item in items"
    :key="item.id"
    :item="item"
    :style="{ gridColumn: item.gridX + 1, gridRow: item.gridY + 1 }"
  >
    {{ item.name }}
  </FreeformItem>
</FreeformGrid>

Items are positioned with plain CSS grid — gridColumn and gridRow are one-based, so a cell at { x: 0, y: 0 } becomes gridColumn: 1, gridRow: 1.

Props

PropTypeDefaultDescription
columnsnumber6Number of columns
rowsnumber4Number of rows
gapstring'8px'CSS gap between cells

Slots

cell

Rendered once per cell, behind the items. Use it to draw the raster.

PropTypeDescription
cell{ x, y }Zero-based cell coordinates
isHoveredbooleanCursor is over this cell during a drag

default

Your items, placed on top of the cells.

PropTypeDescription
hoveredCell{ x, y } | nullCell under the cursor
isDraggingbooleanA drag is in progress

Exposed

Reach these through a template ref:

NameTypeDescription
hoveredCell{ x, y } | nullCell under the cursor
isDraggingbooleanWhether cell tracking is active
onDragStart()functionStart tracking — call on @drag-start
onDragEnd()functionStop tracking — call on @drag-end

Cell tracking only runs between onDragStart() and onDragEnd(), so hovering without dragging does not light up the raster:

vue
<TheFreeform
  v-model="items"
  manual-reorder
  @drag-start="gridRef?.onDragStart()"
  @drag-end="gridRef?.onDragEnd()"
>

Let items fill their cell

FreeformItem sets align-self: flex-start for list layouts. In a grid, give it alignSelf: 'stretch' and minWidth: 0 via :style, otherwise icons sit at the top of their cell and long names blow up the column.

Combining with selection

FreeformGrid works inside FreeformSelection, so lasso and multi-select come for free — see the Grid Desktop example.

MIT Licensed