Getting Started
Installation via CDN
jQuery UI depends on jQuery core — always load jQuery before jquery-ui.js. The CSS provides default theming and is required for widgets like Datepicker and Dialog to display correctly. Version 1.13.x supports jQuery 1.8+.
<!-- jQuery UI requires jQuery core first -->
<link rel="stylesheet"
href="https://code.jquery.com/ui/1.13.2/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.min.js"></script>npm Installation
Installing via npm lets you tree-shake by importing only the widgets you need (e.g. jquery-ui/ui/widgets/datepicker). Importing the full 'jquery-ui' bundle includes every widget and effect. The CSS theme must be imported separately.
# Install via npm
npm install jquery jquery-ui
# Import in your bundle
import $ from "jquery";
import "jquery-ui/ui/widgets/datepicker";
import "jquery-ui/themes/base/all.css";
// Or import the full bundle
import "jquery-ui";Basic Widget Initialization
All jQuery UI widgets follow the same plugin pattern: $(selector).widgetName(options). Pass an options object to configure, call methods via the string syntax ('methodName', args...). Always wrap initialization in $(function(){}) or place script at end of body.
$(function () {
// Initialize a widget on a selector
$("#datepicker").datepicker();
$("#dialog").dialog();
// Pass options as an object
$("#accordion").accordion({
active: false,
collapsible: true,
});
// Get or set an option after init
$("#accordion").accordion("option", "active", 1);
});Widget Method Pattern
The string-based API is consistent across all widgets. 'option' getter/setter, 'enable'/'disable', 'widget' (returns the outermost element), and 'destroy' (restores original markup) are supported by every widget. Use destroy when removing elements to avoid memory leaks.
// All widgets share the same API conventions
$("#dialog").dialog("open"); // call a method
$("#dialog").dialog("option", "title"); // get an option
$("#dialog").dialog("option", "modal", true); // set an option
$("#dialog").dialog("disable"); // disable widget
$("#dialog").dialog("enable"); // enable widget
$("#dialog").dialog("widget"); // get the wrapper element
$("#dialog").dialog("destroy"); // remove widget entirelyTheme Configuration
jQuery UI ships ~24 prebuilt themes. The 'base' theme is the default. ThemeRoller (themroller.jqueryui.com) generates custom themes. Load your own CSS after the base to override specific classes like .ui-widget-header or .ui-state-default.
<!-- Default base theme -->
<link rel="stylesheet"
href="https://code.jquery.com/ui/1.13.2/themes/base/jquery-ui.css">
<!-- Other bundled themes: ui-lightness, ui-darkness, smoothness, redmond, ... -->
<link rel="stylesheet"
href="https://code.jquery.com/ui/1.13.2/themes/smoothness/jquery-ui.css">
<!-- Override theme with your own CSS -->
<link rel="stylesheet" href="jquery-ui.css">
<link rel="stylesheet" href="my-theme-overrides.css">Class Naming Convention
The CSS framework uses a consistent ui-* naming convention. Interaction states (default, hover, active, focus) are applied automatically by widgets. You can use these classes directly in your own markup to match jQuery UI styling.
/* jQuery UI CSS classes are namespaced with ui- */
.ui-widget /* base widget class */
.ui-widget-header /* header bar (accordion, datepicker) */
.ui-widget-content /* content area */
.ui-state-default /* default interactive state */
.ui-state-hover /* mouse-over state */
.ui-state-active /* active/selected state */
.ui-state-focus /* keyboard focus state */
.ui-state-disabled /* disabled state */
.ui-corner-all /* rounded corners (themable) */
.ui-icon /* base icon class */Draggable
Basic Draggable
Making an element draggable is a single call. The element can then be moved with the mouse. The ui-widget-content class applies default theme styling. Draggable inherits positioning — relative/absolute/absolute is applied as needed.
<!-- HTML -->
<div id="box" class="ui-widget-content" style="width:100px;height:100px;">
Drag me
</div>
<!-- JS -->
<script>
$(function () {
$("#box").draggable();
});
</script>Draggable Options
Options control how dragging behaves. 'axis' limits movement to one axis, 'containment' restricts the drag region, 'grid' snaps to intervals, and 'revert' returns the element to its start position. 'helper: clone' drags a copy instead of the original.
$("#box").draggable({
axis: "x", // constrain to x or y axis
containment: "parent", // or "window", "document", or selector
cursor: "move", // cursor while dragging
cursorAt: { left: 5 }, // offset cursor from drag handle
grid: [20, 20], // snap to grid
delay: 100, // ms delay before drag starts
distance: 5, // px before drag starts
revert: true, // snap back to start
revertDuration: 200, // revert animation duration
scroll: false, // prevent auto-scroll
helper: "clone", // "original", "clone", or function
opacity: 0.6, // opacity while dragging
zIndex: 1000, // z-index while dragging
});Drag Events
Three events fire during a drag: 'start' (once at the beginning), 'drag' (continuously while moving), and 'stop' (once at the end). The ui object provides position (relative to parent) and offset (relative to page). Heavy work in 'drag' can hurt performance.
$("#box").draggable({
start: function (event, ui) {
console.log("Drag started", ui.position);
},
drag: function (event, ui) {
// Fires continuously during drag
console.log(ui.position.left, ui.position.top);
},
stop: function (event, ui) {
console.log("Drag stopped at", ui.position);
console.log("Offset:", ui.offset);
},
});Handle & Cancel
'handle' restricts drag initiation to a specific child element — useful when the whole box should be movable but only via a title bar. 'cancel' prevents dragging from certain elements like inputs or textareas where mouse interaction is needed for editing.
<!-- Only the header acts as the drag handle -->
<div id="box" class="ui-widget-content">
<div class="drag-handle">Drag from here</div>
<div class="content">Some content here</div>
<textarea>Editable content</textarea>
</div>
<script>
$("#box").draggable({
handle: ".drag-handle", // only this starts the drag
cancel: "textarea", // these elements never start a drag
});
</script>Constrain Movement
Containment restricts where the element can be dragged. 'parent', 'window', 'document', a selector, or an explicit [x1,y1,x2,y2] array all work. Combined with 'grid', you can create precise, snapped positioning for layout editors or dashboards.
// Constrain within a parent element
$("#box").draggable({ containment: "parent" });
// Constrain within the window
$("#box").draggable({ containment: "window" });
// Constrain within a specific selector
$("#box").draggable({ containment: "#drag-area" });
// Constrain to an explicit bounding box [x1, y1, x2, y2]
$("#box").draggable({ containment: [0, 0, 500, 300] });
// Snap to a 50px grid
$("#box").draggable({ grid: [50, 50] });Snap to Elements
'snap' makes the draggable jump to align with target elements when close enough. 'snapMode' controls alignment: 'inner' (inside target), 'outer' (outside target), or 'both'. Useful for building diagram tools or dashboard layouts where elements should align.
$(".card").draggable({
snap: ".snap-target", // selector of elements to snap to
snapMode: "inner", // "inner", "outer", or "both"
snapTolerance: 30, // px distance to trigger snap
});
// Snap to all siblings of the same class
$(".card").draggable({
snap: ".card",
snapTolerance: 20,
});Droppable
Basic Droppable
Droppable defines a target area that accepts dragged elements. The 'drop' callback fires when a draggable is released over it. The ui.draggable property gives a reference to the dragged element so you can move or process it.
<div id="draggable" class="ui-widget-content">Drag me</div>
<div id="droppable" class="ui-widget-header">Drop here</div>
<script>
$(function () {
$("#draggable").draggable();
$("#droppable").droppable({
drop: function (event, ui) {
$(this).addClass("ui-state-highlight")
.html("Dropped!");
},
});
});
</script>Droppable Options
'accept' filters which draggables are allowed — a selector or function. 'activeClass' and 'hoverClass' provide visual feedback. 'greedy: true' prevents nested droppables from both receiving the drop event, useful for nested drop zones.
$("#droppable").droppable({
accept: ".special", // only accept matching draggables
activeClass: "ui-state-default", // class while a drag is active
hoverClass: "ui-state-hover", // class while draggable is over
tolerance: "fit", // drop detection mode
greedy: true, // stop event propagation
disabled: false, // disable the droppable
});Drop Events
Five events cover the full drop lifecycle. 'activate'/'deactivate' fire when a matching drag starts/ends. 'over'/'out' fire when the draggable enters/leaves the zone. 'drop' fires only on a successful release. Use these for progressive visual feedback.
$("#droppable").droppable({
activate: function (event, ui) {
// Fires when an accepted draggable starts moving
$(this).addClass("ui-state-default");
},
deactivate: function (event, ui) {
// Fires when the drag ends (drop or cancel)
$(this).removeClass("ui-state-default");
},
over: function (event, ui) {
// Draggable entered the drop zone
$(this).addClass("ui-state-hover");
},
out: function (event, ui) {
// Draggable left the drop zone
$(this).removeClass("ui-state-hover");
},
drop: function (event, ui) {
// Draggable was released here
console.log("Dropped:", ui.draggable);
},
});Accept Selector
'accept' can be a selector string or a function returning boolean. The function receives the dragged element and runs for each candidate, letting you apply runtime logic like data attributes or computed states. Unaccepted draggables won't trigger drop events.
<!-- HTML: red and blue boxes -->
<div class="red draggable">Red</div>
<div class="blue draggable">Blue</div>
<div id="red-bin" class="bin">Red bin</div>
<div id="blue-bin" class="bin">Blue bin</div>
<script>
// Only accept elements matching the selector
$("#red-bin").droppable({ accept: ".red" });
$("#blue-bin").droppable({ accept: ".blue" });
// Or use a function for dynamic logic
$("#any-bin").droppable({
accept: function (drag) {
return $(drag).data("category") === "recyclable";
},
});
</script>Tolerance Modes
Tolerance defines how much overlap is required for a drop to register. 'fit' is strictest (entire element inside). 'pointer' is based on the mouse cursor. 'intersect' (50% overlap) is a good balance for most UIs. 'touch' is the most lenient.
$("#droppable").droppable({
// "fit": draggable must be fully inside (default)
tolerance: "fit",
// "intersect": at least 50% overlap
tolerance: "intersect",
// "pointer": mouse pointer must be inside
tolerance: "pointer",
// "touch": any edge touching counts
tolerance: "touch",
});Visual Feedback with Classes
Combine activeClass (shown whenever an accepted drag is in progress) and hoverClass (shown when the draggable is over the zone) to give users clear feedback. In the drop handler, you typically append the draggable to re-parent it into the drop zone.
<!-- CSS -->
<style>
.drop-active { border: 2px dashed #ccc; }
.drop-hover { border: 2px solid #0a0; background: #efe; }
</style>
<!-- JS -->
$("#zone").droppable({
accept: ".item",
activeClass: "drop-active",
hoverClass: "drop-hover",
drop: function (event, ui) {
$(this).append(ui.draggable);
ui.draggable.css({ top: 0, left: 0 });
},
});Resizable
Basic Resizable
Resized adds resize handles to an element. By default a handle appears at the bottom-right (se) corner. The element must have positioning applied (relative/absolute) for the handles to anchor correctly.
<div id="box" class="ui-widget-content">
Resize me from the corner
</div>
<script>
$(function () {
$("#box").resizable();
});
</script>Resize Handles
'handles' controls which edges/corners get resize grips. Use compass directions: n, e, s, w, ne, se, sw, nw. The default is 'e, s, se'. You can provide custom handle elements by selector for full styling control.
$("#box").resizable({
handles: "n, e, s, w, ne, se, sw, nw", // all eight handles
});
// Or specify handle elements
$("#box").resizable({
handles: {
n: ".n-handle",
se: ".se-handle",
},
});Resizable Options
Options constrain and customize resizing. 'aspectRatio' keeps proportions (great for images/video). 'alsoResize' syncs another element. 'ghost' shows a faint preview during resize, with the actual size applied on release. min/max dimensions enforce bounds.
$("#box").resizable({
alsoResize: "#other", // resize another element in sync
animate: true, // animate to final size
animateDuration: 200, // ms
aspectRatio: 16 / 9, // preserve width:height ratio
autoHide: true, // hide handles until hover
containment: "parent", // restrict resize within parent
grid: [10, 10], // snap to grid
maxHeight: 400,
maxWidth: 600,
minHeight: 100,
minWidth: 100,
ghost: true, // show a ghost outline while resizing
});Resize Events
Like draggable, resize fires start/resize/stop. The ui object has 'size' (width, height) and 'position' (left, top). When resizing from north or west edges, both size and position change. Use the resize event to update dependent UI like live preview.
$("#box").resizable({
start: function (event, ui) {
console.log("Resize start", ui.size, ui.position);
},
resize: function (event, ui) {
// Fires continuously during resize
ui.size.width; // new width
ui.size.height; // new height
ui.position.left; // new position (may change for n/w handles)
},
stop: function (event, ui) {
console.log("Final size:", ui.size);
},
});Aspect Ratio & Constraints
Use aspectRatio (a number or boolean true to lock current ratio) for images and media. Combined with min/max constraints, you can prevent awkward sizes. Grid snapping aligns to intervals — useful for editor interfaces and layout tools.
// Keep a 4:3 ratio
$("#photo").resizable({ aspectRatio: 4 / 3 });
// Keep ratio and stay within bounds
$("#photo").resizable({
aspectRatio: 4 / 3,
maxWidth: 800,
maxHeight: 600,
minWidth: 100,
minHeight: 75,
});
// Snap to a grid of 20px
$("#grid-box").resizable({ grid: [20, 20] });Animate & Ghost Modes
'animate' smoothly transitions to the new size after the mouse is released. 'ghost' shows a semi-transparent preview during the drag, applying the real change only on release. Together they create a polished, non-janky resize experience.
// Animate to the final size after release
$("#box").resizable({
animate: true,
animateDuration: "slow", // or ms number
animateEasing: "swing",
});
// Show a ghost outline while dragging, apply on release
$("#box").resizable({
ghost: true,
helper: "ui-resizable-helper", // class for the ghost
});
// Combine both
$("#box").resizable({ ghost: true, animate: true });Selectable
Basic Selectable
Selectable turns a list of children into a selectable group. Click to select, or drag a lasso to select multiple. Hold Ctrl/Cmd to add to the selection, Shift to select a range. Selected items get the ui-selected class automatically.
<ol id="selectable">
<li class="ui-widget-content">Item 1</li>
<li class="ui-widget-content">Item 2</li>
<li class="ui-widget-content">Item 3</li>
</ol>
<script>
$(function () {
$("#selectable").selectable();
});
</script>Selectable Options
'filter' restricts which children participate. 'tolerance' controls lasso behavior: 'touch' selects on any overlap (default), 'fit' requires full enclosure. Set 'autoRefresh: false' for large lists to improve performance — call $(...).selectable('refresh') manually after layout changes.
$("#selectable").selectable({
filter: "li", // which children can be selected
tolerance: "touch", // "touch" or "fit" for lasso overlap
distance: 0, // px before lasso starts
delay: 0, // ms delay before lasso starts
autoRefresh: true, // recompute positions on each drag
disabled: false,
cancel: "a, .no-select", // elements that never start selection
});Select Events
Events fire during the selection lifecycle: 'selecting'/'unselecting' while dragging, 'selected'/'unselected' once confirmed, and 'start'/'stop' for the overall operation. Each ui object has the relevant element (selecting, selected, etc.).
$("#selectable").selectable({
selecting: function (event, ui) {
// ui.selecting: element being lassoed
$(ui.selecting).addClass("highlight");
},
selected: function (event, ui) {
// ui.selected: element just confirmed selected
console.log("Selected:", $(ui.selected).text());
},
unselecting: function (event, ui) {
$(ui.unselecting).removeClass("highlight");
},
unselected: function (event, ui) {
console.log("Unselected:", $(ui.unselected).text());
},
start: function (event, ui) { /* lasso started */ },
stop: function (event, ui) { /* lasso released */ },
});Filter Items
Use 'filter' to allow only specific children to be selected, and 'cancel' to exclude others. This is useful for galleries where some items (locked, read-only) shouldn't participate. The lasso will simply ignore non-matching elements.
<ul id="gallery">
<li class="selectable-item">Photo 1</li>
<li class="locked">Locked</li>
<li class="selectable-item">Photo 2</li>
</ul>
<script>
$("#gallery").selectable({
filter: ".selectable-item", // only these can be selected
cancel: ".locked", // locked items never select
});
</script>Styling Selected Items
jQuery UI applies ui-selecting (during drag) and ui-selected (after release) classes automatically. Style these to give feedback. Read the current selection anytime via $('.ui-selected') within the container — handy for toolbars and bulk actions.
/* CSS */
#selectable .ui-selecting {
background: #feca40; /* while dragging */
}
#selectable .ui-selected {
background: #f39814; /* confirmed selection */
color: white;
}
#selectable li {
margin: 3px; padding: 6px;
border: 1px solid #ccc;
}
/* selected count badge */
function updateCount() {
var n = $("#selectable .ui-selected").length;
$("#count").text(n + " selected");
}
$("#selectable").on("selectablestop", updateCount);Programmatic Selection
Call 'refresh' after adding/removing items so lasso hit-testing stays accurate. There's no built-in 'select' method, but you can toggle the ui-selected class manually. Clear by removing that class from all items.
// Refresh positions after DOM changes
$("#selectable").selectable("refresh");
// Disable / enable
$("#selectable").selectable("disable");
$("#selectable").selectable("enable");
// Remove the widget
$("#selectable").selectable("destroy");
// Manually select an item (set the class)
$("#selectable li").eq(2).addClass("ui-selected");
// Clear all selections
$("#selectable .ui-selected").removeClass("ui-selected");Sortable
Basic Sortable
Sortable makes list items reorderable by drag. Items are visually moved during the drag and the DOM order updates on release. Useful for task lists, photo galleries, and any priority-ordered content.
<ul id="sortable">
<li class="ui-widget-content">Item 1</li>
<li class="ui-widget-content">Item 2</li>
<li class="ui-widget-content">Item 3</li>
</ul>
<script>
$(function () {
$("#sortable").sortable();
});
</script>Sortable Options
Options refine sorting behavior. 'placeholder' styles the gap left behind; forcePlaceholderSize ensures it matches item dimensions. 'axis' restricts to horizontal/vertical. 'handle' designates a drag grip — ideal when the whole item has interactive children.
$("#sortable").sortable({
axis: "y", // constrain to vertical
cursor: "move",
handle: ".handle", // drag from this element only
placeholder: "sortable-placeholder", // class for the drop preview
forcePlaceholderSize: true, // match placeholder to item size
helper: "clone", // "original" or "clone"
opacity: 0.7,
revert: true, // animate item into place
tolerance: "pointer", // "intersect" or "pointer"
scroll: true, // auto-scroll the page
containment: "parent", // restrict within parent
});Sort Events
Key events: 'start'/'stop' bracket the sort. 'change' fires when the item's position changes during drag. 'update' fires only when the final order differs from the start — this is where you persist the new order, often via toArray() which returns item IDs in order.
$("#sortable").sortable({
start: function (event, ui) {
ui.item; // the dragged element
ui.placeholder; // the placeholder element
ui.helper; // the helper being dragged
},
change: function (event, ui) {
// Position in list changed during drag
},
sort: function (event, ui) {
// Fires continuously while sorting
},
beforeStop: function (event, ui) {
// Just before the item is placed
},
stop: function (event, ui) {
console.log("Sort ended");
},
update: function (event, ui) {
// Order actually changed — persist it here
var order = $(this).sortable("toArray");
saveOrder(order);
},
});Connected Lists
'connectWith' links multiple sortables so items can be dragged between them — great for Kanban boards or pipeline managers. Each list still tracks its own order via toArray(). Use receive/remove events to react to cross-list transfers.
<ul id="list-a" class="connected">
<li>Task A1</li><li>Task A2</li>
</ul>
<ul id="list-b" class="connected">
<li>Task B1</li>
</ul>
<script>
$(".connected").sortable({
connectWith: ".connected", // allow moving between lists
placeholder: "ui-state-highlight",
}).disableSelection();
</script>Placeholder & Helper
The placeholder is the empty space shown where the item will land — style it to give clear drop feedback. forcePlaceholderSize is important when items have varying heights. A custom helper function lets you show a simplified preview while dragging.
$("#sortable").sortable({
placeholder: "ui-state-highlight", // class for the gap
forcePlaceholderSize: true,
helper: function (event, el) {
// Return a custom helper element
return $("<div class='custom-helper'>Moving...</div>");
},
cursorAt: { top: 10, left: 10 },
});
// Use a clone as the helper instead of moving the original
$("#sortable").sortable({ helper: "clone" });Sort Methods
toArray() returns IDs in current order — most useful for persistence. serialize() builds a query string when IDs follow the 'name_number' convention. cancel() undoes the most recent sort. Call refresh() after programmatically adding items.
// Get current order as an array of IDs
var order = $("#sortable").sortable("toArray");
// ["item-1", "item-3", "item-2"]
// Get option values
var placeholder = $("#sortable").sortable("option", "placeholder");
// Serialize items as a query string (uses id="name_number")
var data = $("#sortable").sortable("serialize");
// "item[]=1&item[]=2&item[]=3"
// Cancel the current sort (revert)
$("#sortable").sortable("cancel");
// Refresh positions after DOM changes
$("#sortable").sortable("refresh");
// Disable / enable / destroy
$("#sortable").sortable("disable");
$("#sortable").sortable("enable");
$("#sortable").sortable("destroy");Accordion
Basic Accordion
Accordion expects pairs of header + content elements (header must come first). By default only one section is open at a time. The default header element is h3 but can be changed via the header option. Content panels follow each header.
<div id="accordion">
<h3>Section 1</h3>
<div>Content for section 1</div>
<h3>Section 2</h3>
<div>Content for section 2</div>
<h3>Section 3</h3>
<div>Content for section 3</div>
</div>
<script>
$(function () {
$("#accordion").accordion();
});
</script>Accordion Options
Set 'collapsible: true' to allow all panels closed (default forces one open). 'heightStyle: content' sizes each panel to its content; 'fill' makes all panels equal height to the container; 'auto' uses the tallest panel's height.
$("#accordion").accordion({
active: 0, // index of open panel (false = all closed)
collapsible: true, // allow closing all panels
disabled: false,
animate: 200, // ms or "ease name" or false
heightStyle: "content", // "auto", "fill", or "content"
header: "h3", // header selector
icons: {
header: "ui-icon-triangle-1-e",
activeHeader: "ui-icon-triangle-1-s",
},
event: "click", // event that toggles panels
});Accordion Events
beforeActivate lets you veto a panel change by returning false — useful for unsaved-changes prompts. activate fires after the animation completes. The ui object gives old/new header and panel elements for both events.
$("#accordion").accordion({
beforeActivate: function (event, ui) {
// ui.oldHeader, ui.oldPanel (closing)
// ui.newHeader, ui.newPanel (opening)
// Return false to cancel
if ($(ui.newHeader).data("locked")) return false;
},
activate: function (event, ui) {
// Fires after a panel finishes opening
console.log("Opened:", ui.newHeader.text());
},
create: function (event, ui) {
// Fires on initialization
console.log("Accordion created, open:", ui.header.text());
},
});Custom Icons
icons maps the closed (header) and open (activeHeader) icon classes. Pass false to disable icons. You can use any icon library (FontAwesome, Material Icons) by providing the appropriate class names — the icon span is created automatically.
$("#accordion").accordion({
icons: {
header: "ui-icon-circle-arrow-e",
activeHeader: "ui-icon-circle-arrow-s",
},
});
// Disable icons entirely
$("#accordion").accordion({ icons: false });
// Use your own icon classes (e.g. with FontAwesome)
$("#accordion").accordion({
icons: {
header: "fa fa-plus",
activeHeader: "fa fa-minus",
},
});Collapsible & Multiple Sections
For a true 'multiple open at once' accordion, jQuery UI's accordion doesn't support it natively — instead initialize separate collapsible accordions per section, or use tabs. The 'collapsible: true' option only allows closing the currently open panel.