ef-transform-handles

Resize and drag handles for a selected canvas element.

Renders an outlined bounding box with corner/edge resize handles and an optional rotation handle, positioned at bounds. Fires bounds-change on every drag or resize move. pointer-events: none on the host — only the handles themselves capture input.

Consumes panZoomTransformContext to correctly map pointer coordinates when the canvas is panned or zoomed.

AttributeReact propTypeDefaultDescription
canvas-scalecanvasScalenumber1Current canvas zoom scale, used to keep handle hit areas a consistent screen size.
corners-onlycornersOnlybooleanfalseOnly shows corner resize handles, hiding edge handles.
enable-dragenableDragbooleantrueAllows dragging the selection by its body.
enable-resizeenableResizebooleantrueShows resize handles.
enable-rotationenableRotationbooleanfalseShows a rotation handle.
lock-aspect-ratiolockAspectRatiobooleanfalseConstrains resizing to the original aspect ratio.
min-sizeminSizenumberMinimum width/height in pixels during resize.
rotation-steprotationStepnumberSnap increment in degrees while rotating.
<ef-timegroup id="demo" mode="fixed" duration="5s" class="w-[1920px] h-[1080px] bg-slate-900 flex items-center justify-center">
  <style>
    @keyframes pulse {
      0%, 100% { transform: scale(1); }
      50% { transform: scale(1.08); }
    }
    .demo-text { animation: pulse 2.4s ease-in-out infinite; display: inline-block; }
  </style>
  <ef-text class="demo-text text-white text-7xl font-bold">Hello</ef-text>
</ef-timegroup>

<ef-controls target="demo">
  <div class="th-chrome">
    <ef-toggle-play>
      <button slot="play" class="th-btn">▶</button>
      <button slot="pause" class="th-btn">⏸</button>
    </ef-toggle-play>
    <span class="th-hint">ef-transform-handles wraps a canvas element to enable resize and drag</span>
  </div>
</ef-controls>

<style>
  .th-chrome {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 16px;
    border-top: 1px solid rgba(255,255,255,0.08);
  }
  .th-btn { cursor: pointer; padding: 4px 10px; font-size: 13px; }
  .th-hint { font-size: 11px; opacity: 0.4; }
</style>

Typical usage inside an ef-overlay-layer:

<ef-overlay-layer>
  <ef-overlay-item element-id="my-text">
    <ef-transform-handles
      enable-rotation
      enable-resize
      canvas-scale="1"
    ></ef-transform-handles>
  </ef-overlay-item>
</ef-overlay-layer>

Events:

EventDetailDescription
bounds-change{ bounds: { x: number; y: number; width: number; height: number; rotation?: number; } }Fires on every pointer move during a drag or resize.
rotation-change{ rotation: number }Fires during a rotation drag.

Interaction modifiers:

KeyBehavior
ShiftLock aspect ratio during resize
Ctrl / MetaResize from center

CSS Parts

PartDescription
drag-areaInvisible drag surface covering the overlay (when `enable-drag`).
handleEvery resize handle (all 8, or 4 when `corners-only`).
handle-eEast edge resize handle.
handle-nNorth edge resize handle.
handle-neNortheast corner resize handle.
handle-nwNorthwest corner resize handle.
handle-sSouth edge resize handle.
handle-seSoutheast corner resize handle.
handle-swSouthwest corner resize handle.
handle-wWest edge resize handle.
overlayOuter bounding box positioned over the selected element.
rotate-handleRotation handle hit area (when `enable-rotation`).
rotate-handle-circleVisible circular knob inside the rotation handle.
ef-transform-handles::part(handle)    { background: #e94560; }
ef-transform-handles::part(handle-se) { background: #22c55e; }

CSS Custom Properties

An alternative to ::part() for basic color overrides:

PropertyDefaultDescription
--ef-transform-handles-border-colorvar(--ef-color-primary)Outline color of the bounding box overlay.
--ef-transform-handles-dragging-border-colorvar(--ef-color-primary)Bounding box outline color while dragging.
--ef-transform-handles-handle-border-colorvar(--ef-color-primary)Resize handle border color.
--ef-transform-handles-handle-colorvar(--ef-color-bg-elevated)Resize handle fill color.
--ef-transform-handles-rotate-handle-colorvar(--ef-color-success)Rotation handle color.