Skills/Editor Toolkit/Resizable Box Element

ef-resizable-box

Attributes

boundsRequired
BoxBounds

Bounding box dimensions and position

min-size
number

Minimum width and height during resize

Default:10

Resizable container with drag handles for interactive resizing and positioning.

Basic Usage

Display a resizable box:

<div class="relative w-[600px] h-[400px] border border-gray-300 rounded overflow-hidden bg-gray-50">
<ef-resizable-box
.bounds=${{ x: 50, y: 50, width: 200, height: 150 }}
>
<div class="flex items-center justify-center text-gray-600">
Drag handles to resize
</div>
</ef-resizable-box>
</div>

Bounds

Resizable box requires bounds relative to its container:

const box = document.querySelector('ef-resizable-box');
box.bounds = {
x: 100, // Left position
y: 100, // Top position
width: 200, // Width
height: 150 // Height
};

Resize Handles

Eight handles for resizing:

Corner Handles

  • Northwest (top-left)
  • Northeast (top-right)
  • Southwest (bottom-left)
  • Southeast (bottom-right)

Corner handles resize both width and height.

Edge Handles

  • North (top edge) - height only
  • East (right edge) - width only
  • South (bottom edge) - height only
  • West (left edge) - width only

Drag to Move

Click and drag the box content (not handles) to move:

<div class="relative w-[600px] h-[400px] border border-gray-300 rounded overflow-hidden bg-gray-50">
<ef-resizable-box
.bounds=${{ x: 100, y: 80, width: 180, height: 120 }}
>
<div class="flex items-center justify-center text-gray-600 cursor-grab active:cursor-grabbing">
Drag to move
</div>
</ef-resizable-box>
</div>

Events

Listen for bounds changes:

const box = document.querySelector('ef-resizable-box');
box.addEventListener('bounds-change', (e) => {
const { bounds } = e.detail;
console.log('New bounds:', bounds);
// bounds = { x, y, width, height }
});

Events fire during both resize and move operations.

Minimum Size

Set minimum dimensions during resize:

<ef-resizable-box
.bounds=${{ x: 50, y: 50, width: 200, height: 150 }}
min-size="50"
>
Cannot resize below 50x50
</ef-resizable-box>

Container Constraints

Resizable box constrains to its parent container:

<div class="relative w-[400px] h-[300px] border">
<ef-resizable-box
.bounds=${{ x: 20, y: 20, width: 100, height: 80 }}
>
Cannot move or resize outside parent
</ef-resizable-box>
</div>

Box cannot be moved or resized beyond container boundaries.

Visual Feedback

Box shows visual feedback during interaction:

<div class="relative w-[600px] h-[400px] border border-gray-300 rounded overflow-hidden bg-gray-50">
<ef-resizable-box
.bounds=${{ x: 50, y: 50, width: 180, height: 120 }}
>
<div class="flex items-center justify-center">
Interactive Box
</div>
</ef-resizable-box>
</div>

Border and background change during drag operations.

Programmatic Control

Update bounds programmatically:

const box = document.querySelector('ef-resizable-box');
// Animate size
let size = 100;
const interval = setInterval(() => {
size += 10;
if (size > 300) size = 100;
box.bounds = {
x: 50,
y: 50,
width: size,
height: size * 0.75
};
}, 100);

Slotted Content

Add any content inside the box:

<ef-resizable-box .bounds=${{ x: 50, y: 50, width: 200, height: 150 }}>
<img src="image.jpg" class="w-full h-full object-cover">
</ef-resizable-box>

Content fills the box dimensions automatically.

Cursor Styles

Handles show appropriate resize cursors:

  • nw, se: nwse-resize (diagonal)
  • ne, sw: nesw-resize (diagonal)
  • n, s: ns-resize (vertical)
  • e, w: ew-resize (horizontal)
  • content: grab / grabbing (move)

Styling

Resizable box uses CSS custom properties:

ef-resizable-box {
/* Border color */
--ef-resizable-box-border-color: #2196f3;
/* Background color */
--ef-resizable-box-bg-color: rgba(33, 150, 243, 0.2);
/* Border during drag */
--ef-resizable-box-dragging-border-color: #1976d2;
/* Background during drag */
--ef-resizable-box-dragging-bg-color: rgba(33, 150, 243, 0.3);
/* Handle color */
--ef-resizable-box-handle-color: #2196f3;
}

ResizeObserver

Resizable box observes its parent container for size changes:

// Box automatically updates constraints when container resizes
const container = box.offsetParent;
// Container dimensions tracked via ResizeObserver

Comparison with Transform Handles

Use ef-resizable-box when:

  • You need a self-contained resizable container
  • Box is the primary content (not an overlay)
  • Container constraints are important
  • Rotation is not needed

Use ef-transform-handles when:

  • You need to transform existing elements
  • Overlay-style interaction is needed
  • Rotation is required
  • Multi-element selection is needed
  • Integration with ef-canvas is needed

Pointer Events

Resizable box and its handles have pointer-events: auto and capture pointer events during interaction.

Touch Support

Handles use touch-action: none for proper touch device support.

Aspect Ratio

Resizable box does not lock aspect ratio by default. To maintain aspect ratio, handle the bounds-change event:

const box = document.querySelector('ef-resizable-box');
const aspectRatio = box.bounds.width / box.bounds.height;
box.addEventListener('bounds-change', (e) => {
const { bounds } = e.detail;
// Maintain aspect ratio
const newHeight = bounds.width / aspectRatio;
box.bounds = {
...bounds,
height: newHeight
};
});

Handle Features

  • 8 resize handles: nw, n, ne, e, se, s, sw, w (corners and edges)
  • Drag to move: Click and drag the box interior to reposition
  • Visual feedback: Handles show appropriate cursors on hover
  • Constrained sizing: Respects minSize constraint
  • Boundary clipping: Automatically constrained to parent container

Important Notes

  • Position is relative to parent container
  • Must have a positioned parent (relative, absolute, or fixed)
  • Automatically constrained to parent boundaries
  • All handles are always visible (no corners-only mode)
  • Use for simple resize/drag operations without rotation
  • For more advanced transforms, use ef-transform-handles