Lightweight JavaScript Resizable Element Library


Make panels, cards, modals, and layout blocks resizable in plain HTML and JavaScript. hcg-resizable is a zero-dependency library built on the Pointer Events API, so mouse, touch, and pen input share one code path. Eight edge and corner handles, min and max sizing, aspect-ratio locking, and containment are included without jQuery or a framework.

On this page you will find live demos, installation (direct download, npm, CDN), a full options reference, React notes, and copy-paste examples for handles, aspect ratio, containment, and callbacks.

What is hcg-resizable?

hcg-resizable is a lightweight vanilla JavaScript library for making any element resizable. Call new HcgResizable() on a selector or element, pick which edges and corners get handles, constrain size with min, max, aspect ratio, and containment, and listen to onStart, onResize, and onEnd callbacks - without React, jQuery, or any other dependency.

hcg-resizable examples: all handles, corner-only resize, aspect-ratio lock, and containment inside a dashed area
hcg-resizable examples: all handles, corner-only resize, aspect-ratio lock, and containment inside a dashed area.

Why use hcg-resizable?

Most resize solutions are either tied to a framework or ship as part of a large UI toolkit when you only need to stretch a panel or card. jQuery UI Resizable works, but it depends on jQuery and jQuery UI, and touch support needs extra plugins.

hcg-resizable fills that gap: a small, dependency-free library built on Pointer Events for mouse, touch, and pen. It suits vanilla pages, React or Vue dashboards, image crop UIs, and floating panels without pulling in a heavy toolkit. See the comparison table for how it differs from jQuery UI Resizable and hand-rolled scripts, and Features for the full capability list.

Live Demo

Resize the boxes below. Each one shows a different option. For every demo in one place, see the hcg-resizable live demo.

All handles

Drag any edge or corner to resize.

All handles
Corner only (se)

Only the bottom-right corner handle is enabled.

Corner (se)
Aspect ratio locked

Width and height stay proportional while resizing.

Aspect ratio
Contained to parent

The box cannot grow past the dashed stage edges.

Contained
Min and max size

Size is clamped between 80×60 px and 200×160 px.

Min / max

Comparison Table

How hcg-resizable compares with common alternatives.

Feature hcg-resizable jQuery UI resizable Hand-coded resize
File sizeSmall (one JS file + CSS)~90 KB+ (jQuery + jQuery UI)Varies
DependenciesNonejQuery + jQuery UINone
Touch and pen supportYes (Pointer Events)Needs extra pluginManual
Edge and corner handles8 handles (n, e, s, w, ne, se, sw, nw)YesManual
Pick which handlesYes (handles array)YesManual
Min and max sizeYesYesManual
Aspect ratio lockYesYesManual
ContainmentYes (parent or element)YesManual
North/west anchor adjustYes (auto top/left shift)YesManual
Lifecycle callbacksYes (onStart, onResize, onEnd)YesManual
Data attributesYes (data-hcg-* + HcgResizable.init())NoManual

Installation

Direct download

Source code and package:

Or download hcg-resizable.js and hcg-resizable.css and include them directly:

HTML
<link rel="stylesheet" href="hcg-resizable.css">
<script src="hcg-resizable.js"></script>

NPM

Install from npm:

Command Line
npm install hcg-resizable

CommonJS (require):

JavaScript
require("hcg-resizable/hcg-resizable.css");
const HcgResizable = require("hcg-resizable");

ESM (import):

JavaScript
import HcgResizable from "hcg-resizable";
import "hcg-resizable/hcg-resizable.css";

CDN usage

Load from a CDN with two tags - no npm or bundler required. The global HcgResizable constructor is available as soon as the script finishes loading.

jsDelivr:

HTML
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/hcg-resizable@1/hcg-resizable.css">
<script src="https://cdn.jsdelivr.net/npm/hcg-resizable@1/hcg-resizable.js"></script>

unpkg:

HTML
<link rel="stylesheet" href="https://unpkg.com/hcg-resizable@1/hcg-resizable.css">
<script src="https://unpkg.com/hcg-resizable@1/hcg-resizable.js"></script>

Replace @1 or @1.0.0 with the release you want. Load CSS in <head> before the script. You can also self-host by uploading hcg-resizable.js and hcg-resizable.css to your own server.

Basic Usage

Create a positioned element, include the CSS and JS files, then pass a selector or DOM element to new HcgResizable().

HTML
<div id="panel" style="position:absolute;top:40px;left:40px;width:200px;height:120px;border:solid 1px #aaa">
  Drag a handle to resize
</div>
HTML
const resize = new HcgResizable('#panel', {
    onEnd(event, size) {
        console.log('Final size:', size.width, size.height);
    }
});
Pick which handles appear

Pass a handles array with any combination of n, e, s, w, ne, se, sw, and nw.

JavaScript
new HcgResizable('#panel', {
  handles: ['se']   // bottom-right corner only
});

Lock aspect ratio

Set aspectRatio: true to lock the current width/height ratio, or pass a number for a fixed ratio (width / height).

JavaScript
new HcgResizable('#photo', { aspectRatio: true });
new HcgResizable('#photo', { aspectRatio: 16 / 9 });

Keep inside a container (containment)

Set containment: 'parent' to clamp size so the element stays inside its offset parent, or pass an HTMLElement directly.

JavaScript
new HcgResizable('#box', { containment: 'parent' });

new HcgResizable('#box', { containment: '#stage' });

var stage = document.getElementById('stage');
new HcgResizable('#box', { containment: stage });

Min and max size

Clamp width and height while dragging with minWidth, minHeight, maxWidth, and maxHeight.

JavaScript
new HcgResizable('#box', {
  minWidth: 80,
  minHeight: 60,
  maxWidth: 400,
  maxHeight: 300
});

Set size programmatically

Call setSize(width, height) or read the current size with getSize().

JavaScript
var resize = new HcgResizable('#box');
resize.setSize(240, 180);
var size = resize.getSize(); // { width: 240, height: 180 }

Change options at runtime

Use setOption(name, value) or option(name, value) on a live instance. Read values with option(name).

JavaScript
var resize = new HcgResizable('#box', { handles: ['se'] });

resize.setOption('handles', ['n', 'e', 's', 'w', 'ne', 'se', 'sw', 'nw']);
resize.setOption('aspectRatio', true);
resize.setOption('containment', '#stage');
resize.contain();

Features

Everything included in the library at a glance:

  • Zero dependencies - one JS file and one CSS file.
  • Pointer Events - mouse, touch, and pen through one code path.
  • Eight handles - north, east, south, west, and all four corners.
  • Configurable handles - enable only the edges or corners you need.
  • Min and max sizing - clamp width and height during resize.
  • Aspect ratio lock - keep proportions with true or a numeric ratio.
  • Containment - stay inside a parent, a CSS selector, or a specific element.
  • Window resize clamp - contain() runs automatically when the window resizes.
  • North/west anchoring - adjusts top and left when resizing from north or west edges.
  • Size persistence - stores last size in data-hcg-size on the element.
  • Data attributes - data-hcg-resizable plus option attributes; call HcgResizable.init() when ready.
  • Runtime options - change any option later with option() / setOption().
  • Multiple elements - one selector can return an array of instances.
  • Callbacks - onStart, onResize, and onEnd with live size data.
  • Instance API - enable, disable, contain, setSize, getSize, and destroy.
  • UMD / ESM / global - works with bundlers, require, or a plain script tag.
  • Small footprint - tiny library; works in every modern browser.

Using with React

Create the resizable instance inside a useEffect hook and clean it up with destroy() when the component unmounts.

JavaScript
import { useEffect, useRef } from "react";
import HcgResizable from "hcg-resizable";
import "hcg-resizable/hcg-resizable.css";

function Panel() {
  const boxRef = useRef(null);
  const resizeRef = useRef(null);

  useEffect(() => {
    resizeRef.current = new HcgResizable(boxRef.current, {
      handles: ['se'],
      minWidth: 120,
      minHeight: 80,
      onEnd: (event, size) => console.log(size.width, size.height)
    });
    return () => resizeRef.current.destroy();
  }, []);

  return (
    <div ref={boxRef} style={{ position: "absolute", top: 40, left: 40, width: 200, height: 120 }}>
      Resize me
    </div>
  );
}

Data Attributes

Every option that takes a simple value can be set in HTML. Mark elements with data-hcg-resizable, then call HcgResizable.init() once the DOM is ready.

AttributeMaps to optionExample
data-hcg-resizableinit targetdata-hcg-resizable
data-hcg-handleshandlesdata-hcg-handles="se" or "n,e,s,w"
data-hcg-min-widthminWidthdata-hcg-min-width="80"
data-hcg-min-heightminHeightdata-hcg-min-height="60"
data-hcg-max-widthmaxWidthdata-hcg-max-width="400"
data-hcg-max-heightmaxHeightdata-hcg-max-height="300"
data-hcg-aspect-ratioaspectRatiodata-hcg-aspect-ratio="true" or "16/9"
data-hcg-containmentcontainmentdata-hcg-containment="parent" or "#stage"
data-hcg-disableddisableddata-hcg-disabled
data-hcg-sizerestored sizedata-hcg-size="200,120" (written on resize end)
HTML
<div
  data-hcg-resizable
  data-hcg-handles="se"
  data-hcg-containment="parent"
  data-hcg-aspect-ratio="true">
  Resize me
</div>
JavaScript
HcgResizable.init(); // every [data-hcg-resizable] element

To initialize elements added later, call HcgResizable.init() again, or call the constructor directly on the new element.

Options Reference

Pass these as the second argument to new HcgResizable(element, options).

OptionTypeDefaultDescription
handlesString[]all 8Edges and corners to enable: n, e, s, w, ne, se, sw, nw.
minWidthNumber20Minimum width in pixels.
minHeightNumber20Minimum height in pixels.
maxWidthNumberInfinityMaximum width in pixels.
maxHeightNumberInfinityMaximum height in pixels.
aspectRatioBoolean or Numberfalsetrue locks the current ratio; a positive number sets width / height.
containment'parent', String, HTMLElement, or nullnullClamp size so the element stays inside a container. A string is passed to document.querySelector.
disabledBooleanfalseStart in a disabled state. Call enable() to turn resizing on.
onStartFunction or nullnullFired when a resize begins. Receives (event, size).
onResizeFunction or nullnullFired on each pointer move during resize. Receives (event, size).
onEndFunction or nullnullFired when the resize ends. Receives (event, size).

size is { width, height } in pixels.

Instance Methods

The constructor returns a resizable instance with the following methods.

MethodDescription
option(name)Gets an option value.
option(name, value)Sets an option value. Returns the instance for chaining.
setOption(name, value)Alias for option(name, value). Rebuilds handles when handles changes; calls contain() when containment or size limits change.
contain()Re-clamps the current size inside the containment area. Runs automatically on window resize when containment is set.
enable()Turns resizing on. Returns the instance for chaining.
disable()Turns resizing off without removing listeners. Returns the instance.
setSize(width, height)Sets the element size in pixels. Updates data-hcg-size. Returns the instance.
getSize()Returns the current size as { width, height }.
destroy()Removes all handles, listeners, and classes. Use this for SPA or framework cleanup.

Read the library version from the static property:

JavaScript
console.log(HcgResizable.version);

Static helpers on the constructor:

JavaScript
HcgResizable.init();        // every [data-hcg-resizable] element
HcgResizable.destroyAll();  // destroy every active instance

var items = HcgResizable('.panel', { handles: ['se'] });
if (Array.isArray(items)) {
  items.forEach(function (r) { r.disable(); });
}

Callbacks

Pass lifecycle hooks as option functions. Each callback receives the pointer event as the first argument and a size object as the second. Inside the callback, this is the HcgResizable instance.

Function signature
JavaScript
onStart(event, size)  { /* ... */ }
onResize(event, size) { /* ... */ }
onEnd(event, size)    { /* ... */ }
event argument

The first argument is the native browser PointerEvent that triggered the callback. hcg-resizable uses the Pointer Events API, so mouse, touch, and pen input share the same event type.

PropertyTypeDescription
typeStringpointerdown on onStart, pointermove on onResize, pointerup or pointercancel on onEnd.
clientX, clientYNumberPointer position in viewport coordinates (pixels from the top-left of the page).
pointerIdNumberUnique id for this pointer. Useful when several touches are active on the page.
pointerTypeStringmouse, pen, or touch.
buttonNumberMouse button on onStart (0=primary). Not set for touch.
targetHTMLElementThe handle element that received the event.
currentTargetHTMLElementSame as target here: the active resize handle.

You can call event.preventDefault() or event.stopPropagation() in a callback, but hcg-resizable already does this on onStart to avoid unwanted page scrolling or bubbling.

size object

Every callback receives the same size shape with the live dimensions in pixels.

PropertyTypeDescription
widthNumberCurrent width in pixels after constraints are applied.
heightNumberCurrent height in pixels after constraints are applied.
When each callback runs
CallbackWhen it runs
onStartPointer down on a handle; resize begins.
onResizePointer moves while resizing; fires on every move.
onEndPointer released; final size is written to data-hcg-size.
Example
JavaScript
new HcgResizable('#panel', {
  onStart(event, size) {
    console.log(event.pointerType, event.clientX, event.clientY);
    console.log('Started at', size.width, 'x', size.height);
  },
  onResize(event, size) {
    console.log('Resizing to', size.width, 'x', size.height);
  },
  onEnd(event, size) {
    console.log('Finished at', size.width, 'x', size.height);
  }
});

CSS Classes

hcg-resizable adds a few class names you can target for styling. Handle elements are injected into the resizable element.

ClassApplied to
hcg-resizableThe element the instance is attached to.
hcg-resizable-resizingPresent while a resize drag is in progress.
hcg-resizable-disabledPresent while resizing is disabled.
hcg-resize-handleEach injected handle element.
hcg-resize-handle-{dir}Direction-specific handle (n, e, s, w, ne, se, sw, nw).

Browser Support

hcg-resizable works in all modern browsers that support the Pointer Events API.

BrowserSupported
Google ChromeYes
Mozilla FirefoxYes
Microsoft EdgeYes
SafariYes
OperaYes
Mobile browsersYes (touch resizing supported)

License

Released under the MIT License. Free for personal and commercial use. Copyright HTML Code Generator.

Frequently asked questions

Does hcg-resizable have any dependencies?

No. hcg-resizable is plain vanilla JavaScript with zero dependencies. Include hcg-resizable.js and hcg-resizable.css and you are ready to go.

Does hcg-resizable work on touch devices?

Yes. It is built on the Pointer Events API, so mouse, touch, and pen input all work through one code path. Resizable elements set touch-action: none so resizing does not scroll the page accidentally.

Can I lock aspect ratio or keep an element inside a container while resizing?

Yes. Set aspectRatio to true or a number to lock width and height proportionally. Set containment to 'parent' or pass an HTMLElement to clamp size so the element stays inside its container.

Can I use hcg-resizable with React?

Yes. Create the HcgResizable instance inside a useEffect hook, keep a ref to the element, and call destroy() in the cleanup function when the component unmounts. See Using with React on this page.

Can I load hcg-resizable from a CDN?

Yes. Add <link> and <script> tags for hcg-resizable.css and hcg-resizable.js from jsDelivr, unpkg, or your own hosted copy, then call new HcgResizable('.selector'). See Installation and CDN usage on this page.