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.
// Allow all panels to be closed
$("#accordion").accordion({
collapsible: true,
active: false, // start with all closed
});
// Make every section independently toggleable
// (a true multi-open accordion = separate collapsibles)
$(".section").each(function () {
$(this).accordion({
collapsible: true,
active: false,
header: ".section-header",
});
});Dynamic Accordion
Call refresh() after adding or removing panels so the widget re-binds. Use the active option to programmatically open a panel by index. The beforeActivate pattern is a clean way to lazy-load panel content via AJAX only when first opened.
// Refresh after adding content
$("#accordion").append("<h3>New</h3><div>Content</div>");
$("#accordion").accordion("refresh");
// Switch the open panel
$("#accordion").accordion("option", "active", 2);
// Disable / enable
$("#accordion").accordion("disable");
$("#accordion").accordion("enable");
// Destroy
$("#accordion").accordion("destroy");
// Load content on demand (AJAX-style)
$("#accordion").accordion({
beforeActivate: function (event, ui) {
var panel = ui.newPanel;
if (panel.is(":empty")) {
panel.load("/api/section/" + ui.newHeader.data("id"));
}
},
});Autocomplete
Basic Autocomplete
Pass a simple array of strings to 'source' for static suggestions. The widget filters by substring as the user types. Suggestions appear in a dropdown; selecting one fills the input. The list can also contain {label, value} objects for richer display.
<label for="city">City:</label>
<input id="city" type="text">
<script>
$(function () {
var cities = ["London", "Paris", "Berlin", "Madrid", "Rome"];
$("#city").autocomplete({ source: cities });
});
</script>Remote Data Source
When source is a URL, autocomplete sends a GET request with ?term= typed text and expects a JSON array. minLength delays the request until enough characters are typed to reduce server load. The delay option debounces rapid typing.
$("#city").autocomplete({
source: "/api/cities", // server endpoint
minLength: 2, // start suggesting after 2 chars
delay: 300, // ms between keystroke and request
});
// The server should return JSON like:
// ["London", "Paris", "Berlin"]
// or [{ "label": "London, UK", "value": "London" }]Autocomplete Options
autoFocus: true highlights the first suggestion so pressing Enter selects it immediately. position configures menu placement relative to the input using jQuery UI Position. appendTo is useful when the input is in an absolutely-positioned container with overflow issues.
$("#city").autocomplete({
source: cities, // array, URL, or function
minLength: 1, // chars before suggestions appear
delay: 300, // ms between keystroke and request
autoFocus: true, // focus first item automatically
appendTo: "#container", // where to render the menu
position: { my: "left top", at: "left bottom" },
disabled: false,
});Custom Source Function
A function source gives full control — useful for caching, custom filtering, or combining multiple endpoints. You MUST call response(results) with an array, even if empty. Each item can have arbitrary fields beyond label/value, accessible in the select handler.
$("#city").autocomplete({
source: function (request, response) {
// request.term is the typed text
// response() must be called with the results array
$.getJSON("/api/cities", { q: request.term })
.done(function (data) {
response(data);
})
.fail(function () {
response([]); // always call response, even on error
});
},
select: function (event, ui) {
// ui.item.label, ui.item.value
$("#city-id").val(ui.item.id);
},
});Autocomplete Events
focus fires as the user moves through suggestions (keyboard or hover). select fires when an item is chosen. change fires on blur and is the right place to validate that the final value exists in the source. Returning false prevents the default input-filling behavior.
$("#city").autocomplete({
source: cities,
focus: function (event, ui) {
// Fires when an item is highlighted (not selected)
$("#preview").text(ui.item.label);
return false; // prevent setting the input value on focus
},
select: function (event, ui) {
// Fires when an item is chosen
$("#city").val(ui.item.label);
$("#city-id").val(ui.item.value);
return false; // prevent default behavior
},
change: function (event, ui) {
// Fires when input loses focus
if (!ui.item) {
// User typed something not in the list
console.log("No match:", this.value);
}
},
});Categories & Custom Rendering
Override _renderMenu or _renderItem to customize the dropdown layout. This example groups suggestions by category with header rows. The $.widget pattern extends the base autocomplete, so all original options and events still work. Common for search interfaces.
$.widget("custom.catcomplete", $.ui.autocomplete, {
_renderMenu: function (ul, items) {
var that = this, currentCategory = "";
$.each(items, function (index, item) {
if (item.category !== currentCategory) {
ul.append("<li class='ui-autocomplete-category'>"
+ item.category + "</li>");
currentCategory = item.category;
}
that._renderItemData(ul, item);
});
},
});
// Use the new widget
$("#search").catcomplete({
source: [
{ label: "Java", category: "Languages" },
{ label: "JavaScript", category: "Languages" },
{ label: "React", category: "Frameworks" },
],
});Datepicker
Basic Datepicker
Clicking or focusing the input opens a calendar popup. The selected date fills the input as text. The calendar shows the current month with navigation arrows for previous/next month. By default dates use the US format (mm/dd/yy).
<label for="date">Pick a date:</label>
<input type="text" id="date">
<script>
$(function () {
$("#date").datepicker();
});
</script>Datepicker Options
minDate/maxDate accept a Date object, a number (days from today), or a string ('+1M +1W'). numberOfMonths displays multiple months — helpful for date-range pickers. changeMonth/changeYear add dropdowns for jumping to distant years.
$("#date").datepicker({
dateFormat: "yy-mm-dd", // ISO format
defaultDate: "+1", // tomorrow when calendar opens
minDate: 0, // no past dates (today+)
maxDate: "+1Y", // up to one year ahead
numberOfMonths: 2, // show 2 months side by side
showButtonPanel: true, // Today/Done buttons
changeMonth: true, // dropdown for month
changeYear: true, // dropdown for year
showAnim: "fadeIn", // open animation
duration: "fast",
firstDay: 1, // start week on Monday
showWeek: true, // show week numbers
});Date Format
The dateFormat option uses PHP-style tokens. 'yy' means four-digit year (the extra y is intentional). Use formatDate() method to convert a Date to a string with the same tokens, and parseDate() to reverse it.
$("#date").datepicker({
dateFormat: "yy-mm-dd", // 2026-07-04
});
// Format tokens:
// d - day of month, no leading zero (1)
// dd - day, two digits (01)
// D - short day name (Mon)
// DD - full day name (Monday)
// m - month, no leading zero (1)
// mm - month, two digits (01)
// M - short month name (Jan)
// MM - full month name (January)
// y - two-digit year (26)
// yy - four-digit year (2026)
// @ - Unix timestamp
// ! - Windows ticks
// Common formats:
// "mm/dd/yy" -> 07/04/2026
// "yy-mm-dd" -> 2026-07-04
// "DD, MM d, yy" -> Friday, July 4, 2026Min/Max Dates & Ranges
For a date-range picker, link two datepickers: when the start is chosen, set the end's minDate; when the end is chosen, set the start's maxDate. beforeShowDay lets you disable or style individual days — noWeekends is a built-in that blocks Saturdays and Sundays.
// Restrict to a date range
$("#start").datepicker({
minDate: 0,
maxDate: "+6M",
onSelect: function (dateText) {
// Set the end date's minimum to the start date
$("#end").datepicker("option", "minDate", dateText);
},
});
$("#end").datepicker({
minDate: 0,
maxDate: "+6M",
onSelect: function (dateText) {
$("#start").datepicker("option", "maxDate", dateText);
},
});
// Disable weekends
$("#date").datepicker({
beforeShowDay: $.datepicker.noWeekends,
});Localization
jQuery UI ships regional files in the i18n folder for ~40 locales. Load the file and apply with $.datepicker.regional['fr']. You can also override individual strings inline. The regional file sets month names, day names, firstDay, and dateFormat at once.
// Set the regionalization
$("#date").datepicker($.datepicker.regional["fr"]);
// Override specific strings
$("#date").datepicker({
monthNames: ["janvier","février","mars","avril","mai","juin",
"juillet","août","septembre","octobre","novembre","décembre"],
dayNamesMin: ["Di","Lu","Ma","Me","Je","Ve","Sa"],
firstDay: 1,
dateFormat: "dd/mm/yy",
prevText: "Précédent",
nextText: "Suivant",
closeText: "Fermer",
currentText: "Aujourd'hui",
});
// Include the regional file for built-in locales:
// <script src="jquery-ui/i18n/datepicker-fr.js"></script>Inline Datepicker & Events
Apply datepicker to a div instead of an input for an always-visible inline calendar — great for booking interfaces. onSelect fires when a date is picked, onChangeMonthYear when navigating months. getDate/setDate work with Date objects for programmatic control.
<!-- Inline (always visible) calendar -->
<div id="inline-calendar"></div>
<script>
$("#inline-calendar").datepicker({
onSelect: function (dateText, inst) {
console.log("Selected:", dateText);
},
onChangeMonthYear: function (year, month, inst) {
console.log("Viewing:", month + "/" + year);
},
beforeShow: function (input, inst) {
// Fires before the popup opens
return { /* override options */ };
},
onClose: function (dateText, inst) {
// Fires when the popup closes
},
});
// Methods
$("#date").datepicker("setDate", "+7"); // set to a week from today
$("#date").datepicker("getDate"); // returns a Date object
$("#date").datepicker("option", "minDate", new Date(2026, 0, 1));
</script>Dialog
Basic Dialog
The element's title attribute becomes the dialog title bar. The dialog is auto-opened by default and is draggable/resizable. The element is moved into a jQuery UI wrapper with proper z-index stacking. Close via the X button or pressing Escape.
<div id="dialog" title="Basic dialog">
<p>This is a simple dialog window.</p>
</div>
<script>
$(function () {
$("#dialog").dialog();
});
</script>Dialog Options
Set autoOpen: false to create the dialog hidden, then call dialog('open') when needed — this is the standard pattern for on-demand dialogs. modal adds an overlay that blocks page interaction. position uses the jQuery UI Position utility for precise placement.
$("#dialog").dialog({
autoOpen: false, // don't open on init
modal: true, // dim the page behind
width: 400,
height: "auto",
minWidth: 200,
maxWidth: 600,
resizable: true,
draggable: true,
closeOnEscape: true,
position: { my: "center", at: "center", of: window },
title: "Custom Title", // override the title attr
show: { effect: "fade", duration: 200 },
hide: { effect: "fade", duration: 200 },
});Dialog Buttons
buttons accepts an array (preferred, allows icons and per-button options) or an object (text: handler). Inside a handler, 'this' is the dialog element — call $(this).dialog('close') to dismiss. Buttons are auto-themed and right-aligned by default.
$("#dialog").dialog({
buttons: [
{
text: "Save",
icon: "ui-icon-disk",
click: function () {
saveForm();
$(this).dialog("close");
},
},
{
text: "Cancel",
click: function () {
$(this).dialog("close");
},
},
],
});
// Shortcut object form (1.12+)
$("#dialog").dialog({
buttons: {
"Save": function () { saveForm(); $(this).dialog("close"); },
"Cancel": function () { $(this).dialog("close"); },
},
});Dialog Events
beforeClose is the gatekeeper — return false to keep the dialog open (useful for unsaved-changes warnings). close fires after the dialog is dismissed, the right place to reset form state or free resources. drag/resize events mirror those of the underlying interactions.
$("#dialog").dialog({
beforeClose: function (event, ui) {
// Return false to prevent closing
if (!confirm("Discard changes?")) return false;
},
open: function (event, ui) {
console.log("Dialog opened");
},
close: function (event, ui) {
console.log("Dialog closed");
// Clean up form state
$(this).find("form")[0].reset();
},
focus: function (event, ui) {
// Dialog gained focus
},
dragStart: function (event, ui) { /* dragging started */ },
dragStop: function (event, ui) { /* dragging ended */ },
resizeStart: function (event, ui) { /* resizing started */ },
resizeStop: function (event, ui) { /* resizing ended */ },
});Modal & Confirmation Dialog
Create a dialog from a dynamically-built element for one-off confirmations. The modal overlay prevents interaction with the rest of the page. Always destroy and remove the element in the close handler to avoid leaking DOM nodes when the dialog is dismissed.
function confirmDialog(message, onConfirm) {
$("<div>" + message + "</div>").dialog({
modal: true,
title: "Confirm",
buttons: {
"OK": function () {
onConfirm();
$(this).dialog("close");
},
"Cancel": function () {
$(this).dialog("close");
},
},
close: function () {
$(this).dialog("destroy").remove(); // clean up
},
});
}
// Usage
confirmDialog("Delete this item?", function () {
deleteItem();
});AJAX Content & Methods
Use the open event to AJAX-load content and initialize any nested widgets. Always clear content on close so the next open is fresh. moveToTop raises the dialog above others in z-index — useful for stacked dialogs. isOpen is a boolean getter for conditional logic.
// Load content from a URL when opening
function openEditDialog(id) {
var $dlg = $("#edit-dialog");
$dlg.dialog({
autoOpen: false,
modal: true,
open: function () {
$dlg.load("/api/edit/" + id, function () {
// Initialize widgets in loaded content
$dlg.find(".datepicker").datepicker();
});
},
close: function () {
$dlg.empty(); // clear for next open
},
});
$dlg.dialog("open");
}
// Common methods
$("#dialog").dialog("open");
$("#dialog").dialog("close");
$("#dialog").dialog("isOpen"); // returns boolean
$("#dialog").dialog("moveToTop"); // bring to front
$("#dialog").dialog("option", "title", "New Title");Progressbar
Basic Progressbar
Progressbar shows a horizontal bar filled to a percentage (0-100). The value option sets the current progress. The bar auto-themes with jQuery UI styling. The container's width determines the total bar width — set it via CSS.
<div id="progress"></div>
<script>
$(function () {
$("#progress").progressbar({ value: 37 });
});
</script>Indeterminate Mode
Setting value to false puts the bar in indeterminate mode — an animated stripe indicates 'something is happening' without a specific percent. Use this when the total is unknown (e.g. waiting on a server). Switch back to a number once you can track progress.
<div id="progress"></div>
<script>
// Set value to false for an indeterminate (animated) bar
$("#progress").progressbar({ value: false });
// Switch to determinate later when you know the percent
$("#progress").progressbar("option", "value", 50);
</script>Progressbar Options
The 'max' option lets you use non-100 scales (e.g. max: 1000 for a download in KB). The value is interpreted as a fraction of max. The classes option (1.12+) lets you add custom classes to specific internal elements for fine-grained theming.
$("#progress").progressbar({
value: 0, // 0-100, or false for indeterminate
max: 100, // upper bound (default 100)
disabled: false,
// 1.12+ supports a 'classes' option for theming
classes: {
"ui-progressbar": "highlight",
"ui-progressbar-value": "animated",
},
});Updating Value
Update the bar by setting the value option. A setInterval loop simulates progress for uploads or long-running tasks. For real uploads, use the XHR upload progress event to update value based on bytes transferred. Always clear the timer when done.
// Simulate a file upload
var progress = 0;
$("#progress").progressbar({ value: 0 });
var timer = setInterval(function () {
progress += 5;
$("#progress").progressbar("option", "value", progress);
if (progress >= 100) {
clearInterval(timer);
console.log("Complete!");
}
}, 200);
// Get current value
var current = $("#progress").progressbar("option", "value");Change Event & Custom Labels
change fires whenever the value updates, complete fires at 100% — both are useful for dynamic styling or labels. To show the percentage text, add an absolutely-positioned label over the bar. Update it inside the change handler to keep it in sync.
$("#progress").progressbar({
value: 0,
change: function () {
var v = $("#progress").progressbar("value");
$("#progress .ui-progressbar-value")
.css("background", v < 50 ? "#fa0" : "#0a0");
},
complete: function () {
$("#progress .ui-progressbar-value").css("background", "#0a0");
$("#progress-label").text("Done!");
},
});
// Overlay a text label
$("#progress").append(
'<div id="progress-label" style="position:absolute;left:50%;top:0;">Loading...</div>'
);Slider
Basic Slider
Slider creates a draggable handle on a horizontal track. The default range is 0-100 with the handle starting at 0. The track is fully themed. Set dimensions via CSS on the container — width for horizontal, height for vertical sliders.
<div id="slider"></div>
<script>
$(function () {
$("#slider").slider();
});
</script>Slider Options
Use 'values' (array) instead of 'value' for a two-handle range slider. 'range: true' shades the area between handles; 'range: min' shades from the handle to the min; 'range: max' shades from the handle to the max. 'step' must divide evenly into (max - min).
$("#slider").slider({
min: 0,
max: 100,
step: 1, // increment size
value: 50, // single value
values: [25, 75], // two-handle range (omit 'value')
orientation: "horizontal", // or "vertical"
range: true, // or "min", "max"
disabled: false,
animate: "fast", // or ms, or false
});Slider Events
slide fires continuously during dragging — ideal for live-updating a label. Returning false inside slide cancels the movement, useful for constraining values dynamically. change fires after release and on programmatic option changes; use it to persist the value.
$("#slider").slider({
start: function (event, ui) {
// User started dragging a handle
console.log("Start:", ui.value || ui.values);
},
slide: function (event, ui) {
// Fires continuously during drag
// Return false to prevent the handle from moving
$("#label").text(ui.value);
},
change: function (event, ui) {
// Fires after the handle is released (and on programmatic change)
saveValue(ui.value);
},
stop: function (event, ui) {
// User released the handle
},
});Range Slider
A two-handle range slider is built by setting range: true and providing a values array. ui.values[0] is the lower handle, ui.values[1] is the upper. The handles cannot cross. This is the classic pattern for price or date-range filters.
<div id="range-slider"></div>
<p>Price: $<span id="min-price"></span> - $<span id="max-price"></span></p>
<script>
$("#range-slider").slider({
range: true,
min: 0,
max: 500,
values: [75, 300],
slide: function (event, ui) {
$("#min-price").text(ui.values[0]);
$("#max-price").text(ui.values[1]);
},
});
</script>Vertical & Orientations
Vertical sliders need an explicit height set via CSS — width applies to the cross-axis. The handle moves up/down instead of left/right. The range shading works the same way. Useful for audio mixers, equalizers, or any UI where vertical orientation is more natural.
// Vertical slider
$("#vertical").slider({
orientation: "vertical",
min: 0,
max: 100,
value: 60,
});
// Vertical range
$("#vertical-range").slider({
orientation: "vertical",
range: true,
min: 0,
max: 100,
values: [20, 80],
});
/* CSS: vertical sliders need a height */
/* #vertical { height: 200px; } */
</script>Slider Methods
For range sliders, use values() (no args) to get an array, values(index, value) to set one handle, or values(array) to set both. Setting options like min/max/step at runtime automatically re-positions the handles within the new bounds.
// Get or set the value
$("#slider").slider("value");
$("#slider").slider("value", 75);
// Get or set both handles of a range slider
var vals = $("#slider").slider("values"); // [25, 75]
$("#slider").slider("values", 0, 30); // set lower handle
$("#slider").slider("values", [30, 90]); // set both
// Get or set options
$("#slider").slider("option", "max", 200);
$("#slider").slider("option", "disabled", true);
// Disable / enable / destroy
$("#slider").slider("disable");
$("#slider").slider("enable");
$("#slider").slider("destroy");Spinner
Basic Spinner
Spinner adds up/down buttons to a text input for numeric entry. Users can type directly, click the buttons, or use the arrow keys. Holding a button accelerates the increment. The input's value is parsed as a number on every change.
<label for="qty">Quantity:</label>
<input id="qty" type="text" value="1">
<script>
$(function () {
$("#qty").spinner();
});
</script>Spinner Options
min/max enforce bounds — the buttons won't go beyond them. step controls increment size (use decimals like 0.1 for fine control). numberFormat with culture enables localized formatting (e.g. 'C' with 'ja-JP' shows yen). Globalize.js must be loaded for culture support.
$("#qty").spinner({
min: 0, // minimum value
max: 100, // maximum value
step: 1, // increment size
page: 10, // page up/down increment
numberFormat: "n", // "n" for number, "C" for currency
culture: "en-US", // locale for formatting
disabled: false,
incremental: true, // accelerate while holding
icons: {
up: "ui-icon-triangle-1-n",
down: "ui-icon-triangle-1-s",
},
});Number Formatting & Culture
With Globalize.js loaded, spinner formats values per the specified culture — currency symbols, decimal separators, and grouping all localize. numberFormat 'C' is currency, 'n' is number with optional decimal count (n2 = 2 decimals). Useful for internationalized forms.
<!-- Requires Globalize.js for culture support -->
<script src="globalize.js"></script>
<script src="globalize.culture.ja-JP.js"></script>
<script>
// Currency spinner (Japanese yen)
$("#price").spinner({
numberFormat: "C",
culture: "ja-JP",
step: 100,
min: 0,
});
// Decimal spinner
$("#weight").spinner({
step: 0.01,
numberFormat: "n2", // 2 decimal places
min: 0,
});
</script>Spinner Events
spin fires on each increment/decrement (button click or arrow key). Returning false cancels the change — ideal for custom validation. change fires on blur; ui.value is null if the input doesn't parse as a valid number, the place to show validation errors.
$("#qty").spinner({
spin: function (event, ui) {
// Fires when a button is clicked or arrow pressed
// ui.value is the new value
// Return false to cancel the change
if (ui.value > 10) {
alert("Max 10 per order");
return false;
}
},
change: function (event, ui) {
// Fires when the value changes and input loses focus
// ui.value may be null if invalid
if (ui.value === null) {
alert("Please enter a valid number");
}
},
start: function (event, ui) { /* spin started */ },
stop: function (event, ui) { /* spin stopped */ },
});Custom Step & Methods
stepUp/stepDown/pageUp/pageDown simulate button presses programmatically. value() with no argument is a getter; with an argument it's a setter that runs through validation. Custom spin handlers let you build non-numeric spinners like times, colors, or custom units.
// Time spinner (steps of 15 minutes)
$("#time").spinner({
step: 15,
min: 0,
max: 1439, // 24 * 60 - 1
numberFormat: "n0",
spin: function (event, ui) {
// Wrap around at midnight
if (ui.value > 1439) return false; // or wrap: $(this).spinner("value", 0);
},
});
// Methods
$("#qty").spinner("value"); // get current value
$("#qty").spinner("value", 5); // set value
$("#qty").spinner("stepUp"); // increment by one step
$("#qty").spinner("stepDown"); // decrement by one step
$("#qty").spinner("pageUp"); // increment by 'page' steps
$("#qty").spinner("pageDown");
$("#qty").spinner("disable");
$("#qty").spinner("enable");
$("#qty").spinner("destroy");Validation & Custom Parsing
Override _parse and _format to build spinners for non-decimal values — hex colors, times, angles, or any custom unit. _parse converts the input text to a number; _format converts back for display. This is the cleanest way to extend spinner for domain-specific inputs.
// Custom spinner for hexadecimal colors
$.widget("custom.hexspinner", $.ui.spinner, {
_parse: function (value) {
// String -> number
return parseInt(value, 16);
},
_format: function (value) {
// number -> string
return value.toString(16).toUpperCase().padStart(6, "0");
},
});
$("#color").hexspinner({
min: 0x000000,
max: 0xffffff,
step: 0x10,
});
// Prevent invalid input
$("#qty").on("keydown", function (e) {
if (e.key === "-" && $(this).spinner("option", "min") >= 0) {
e.preventDefault();
}
});Tabs
Basic Tabs
Tabs expects a ul of links pointing to content panel IDs, followed by the panels themselves. The link hrefs (#tab-1) connect tabs to panels. The first tab is active by default. Tabs are keyboard-navigable (arrows, Home, End) and ARIA-compliant.
<div id="tabs">
<ul>
<li><a href="#tab-1">First</a></li>
<li><a href="#tab-2">Second</a></li>
<li><a href="#tab-3">Third</a></li>
</ul>
<div id="tab-1">Content 1</div>
<div id="tab-2">Content 2</div>
<div id="tab-3">Content 3</div>
</div>
<script>
$(function () {
$("#tabs").tabs();
});
</script>Tabs Options
active sets the initially open tab by index (or false to start collapsed). heightStyle 'fill' makes all panels equal to the container height; 'content' sizes each to its own content (default). 'event: mouseover' creates hover-activated tabs.
$("#tabs").tabs({
active: 0, // index of active tab (false = all hidden)
collapsible: false, // allow closing the active tab
disabled: [], // array of disabled indices
event: "click", // event to switch tabs ("mouseover" etc.)
heightStyle: "content", // "auto", "fill", or "content"
show: { effect: "fadeIn", duration: 200 },
hide: { effect: "fadeOut", duration: 200 },
});Tabs Events
beforeActivate is the gatekeeper — return false to block switching (e.g. unsaved changes warning). activate fires after the switch completes. beforeLoad/load are for AJAX tabs — beforeLoad lets you customize or cancel the request; load fires on success.
$("#tabs").tabs({
beforeActivate: function (event, ui) {
// ui.newTab, ui.newPanel (opening)
// ui.oldTab, ui.oldPanel (closing)
// Return false to cancel the switch
if ($(ui.newPanel).find("form").hasUnsavedChanges()) {
return confirm("Discard changes?");
}
},
activate: function (event, ui) {
// Fires after the new tab is shown
console.log("Now on:", ui.newTab.text());
},
beforeLoad: function (event, ui) {
// For AJAX tabs — fires before loading remote content
ui.jqXHR.error(function () {
ui.panel.text("Failed to load content.");
});
},
load: function (event, ui) {
// AJAX content finished loading
},
});AJAX Tabs
When a tab's href is a URL (not an anchor), tabs loads the content via AJAX on activation. The response replaces the panel. beforeLoad lets you show a spinner, configure the AJAX request, or cancel it. Loaded content is cached for the session by default in 1.12+.
<div id="tabs">
<ul>
<li><a href="#local">Local</a></li>
<li><a href="remote.html">Remote (AJAX)</a></li>
<li><a href="api/data.json">API Data</a></li>
</ul>
<div id="local">This content is in the page.</div>
<!-- Remote panels are created automatically -->
</div>
<script>
$("#tabs").tabs({
beforeLoad: function (event, ui) {
// Show a loading indicator
ui.panel.html("Loading...");
// Cache the loaded content
ui.ajaxSettings.cache = true;
},
});
</script>Collapsible & Sortable Tabs
With collapsible: true, clicking the active tab closes it (no tab remains open). Pairing tabs with sortable on the nav lets users reorder tabs by dragging. After adding or removing tabs/panels, call refresh() so the widget re-binds the new structure.
// Allow collapsing the active tab
$("#tabs").tabs({ collapsible: true });
// Make tabs reorderable by drag
$("#tabs").tabs().find(".ui-tabs-nav").sortable({
axis: "x",
stop: function () {
$("#tabs").tabs("refresh");
},
});
// Dynamically add a new tab
function addTab(id, label, content) {
var nav = $("#tabs .ui-tabs-nav");
nav.append('<li><a href="#' + id + '">' + label + '</a></li>');
$("#tabs").append('<div id="' + id + '">' + content + '</div>');
$("#tabs").tabs("refresh");
}Tabs Methods
disable/enable accept an index or array of indices. The active option is both getter and setter for the current tab — use it to programmatically switch. load() reloads AJAX content for a tab. refresh() is essential after adding, removing, or reordering tabs.
// Disable / enable specific tabs
$("#tabs").tabs("disable", 1); // disable second tab
$("#tabs").tabs("enable", 1);
$("#tabs").tabs("option", "disabled", [0, 2]); // disable multiple
// Switch to a tab by index
$("#tabs").tabs("option", "active", 2);
// Reload an AJAX tab
$("#tabs").tabs("load", 1);
// Refresh after structural changes
$("#tabs").tabs("refresh");
// Get the active tab index
var active = $("#tabs").tabs("option", "active");
// Destroy
$("#tabs").tabs("destroy");Tooltip
Basic Tooltip
Calling tooltip() on document replaces all native title tooltips with themed jQuery UI versions. The title attribute content becomes the tooltip text. Tooltips appear on hover and disappear on mouseout, with smooth fade animation by default.
<label for="age">Age:</label>
<input id="age" title="Please enter your age in years">
<script>
$(function () {
$(document).tooltip();
});
</script>Tooltip Options
Override 'content' as a function to generate dynamic tooltip HTML (e.g. from data attributes or AJAX). 'items' is a selector controlling which elements trigger tooltips. 'track: true' makes the tooltip follow the cursor — useful for detailed help text on diagrams.
$(document).tooltip({
content: function () {
// Default: returns the element's title attribute
return $(this).attr("title");
},
items: "[title]", // which elements get tooltips
position: { my: "left top+15", at: "left bottom" },
show: { effect: "fadeIn", duration: 200 },
hide: { effect: "fadeOut", duration: 200 },
tooltipClass: "custom-tooltip", // class for the tooltip div
track: false, // follow the mouse cursor
disabled: false,
close: null, // (event defaults handle this)
});Custom Content
The content function lets you build rich tooltips with HTML, images, or AJAX-fetched content. Return a string (HTML allowed). tooltipClass adds a custom class for styling. This is the standard pattern for thumbnail previews or help bubbles on form fields.
<!-- HTML with data attributes -->
<a href="#" class="help" data-help="Click to save your changes">Save</a>
<a href="#" class="help" data-help="Undo the last action">Undo</a>
<script>
$(".help").tooltip({
content: function () {
return "<strong>Help:</strong> " + $(this).data("help");
},
tooltipClass: "help-tooltip",
});
</script>
<!-- With an image preview -->
$(".thumb").tooltip({
content: function () {
var src = $(this).attr("href");
return "<img src='" + src + "' width='200'>";
},
});Tooltip Events
open and close fire as tooltips appear and disappear. The ui.tooltip property gives the tooltip element for customization. A common pattern is keeping the tooltip open while the user hovers over it — useful when the tooltip contains interactive content like links.
$(".help").tooltip({
open: function (event, ui) {
// Tooltip just appeared
ui.tooltip; // the tooltip element
},
close: function (event, ui) {
// Tooltip just disappeared
ui.tooltip.one("transitionend", function () {
// Cleanup after the hide animation
});
},
create: function (event, ui) {
// Widget initialized
},
});
// Prevent tooltip from closing on hover
$(".help").tooltip({
close: function (event, ui) {
ui.tooltip.hover(
function () { $(this).stop(true).fadeIn(); },
function () { $(this).fadeOut(); }
);
},
});Position & Methods
Position uses the jQuery UI Position utility: 'my' is the tooltip's anchor, 'at' is the target's anchor. collision handles edge cases — 'flip' moves to the other side if it would overflow. open()/close() show/hide tooltips programmatically, useful for validation errors.
$("#target").tooltip({
position: {
my: "center top", // tooltip's anchor point
at: "center bottom", // target's anchor point
of: "#target", // optional: position relative to this
collision: "flip", // "flip", "fit", "flipfit", "none"
using: function (pos, feedback) {
$(this).css(pos);
console.log(feedback.horizontal, feedback.vertical);
},
},
});
// Methods
$("#target").tooltip("open"); // show programmatically
$("#target").tooltip("close"); // hide programmatically
$("#target").tooltip("disable");
$("#target").tooltip("enable");
$("#target").tooltip("widget"); // get the tooltip div
$("#target").tooltip("destroy");Form Validation Tooltips
Tooltips are a clean way to show inline validation errors. Store the error message in a data attribute, set content to read it, and call open() to display. Returning false in the open handler prevents the tooltip when there's no error. Style with tooltipClass for red error styling.
<!-- Show validation errors as tooltips -->
<form id="form">
<input id="email" type="text" placeholder="Email">
<input id="submit" type="submit" value="Submit">
</form>
<script>
$("#form").tooltip({
items: "input",
content: function () {
return $(this).data("error") || "";
},
position: { my: "left top", at: "left bottom+5" },
tooltipClass: "error-tooltip",
open: function (event, ui) {
var el = $(event.originalEvent.target);
if (!el.data("error")) return false; // don't show if no error
},
});
$("#submit").on("click", function (e) {
var email = $("#email").val();
if (!email.includes("@")) {
e.preventDefault();
$("#email").data("error", "Please enter a valid email")
.tooltip("open");
}
});
</script>Effects
Core Effects
jQuery UI extends jQuery's show/hide/toggle with named effects and adds the .effect() method for non-hiding animations. Each accepts an options object, duration, and callback. 'transfer' creates a transfer element outline — useful for drag-to-cart animations.
// Built-in effects (beyond jQuery's show/hide/toggle)
$("#box").hide("fade", {}, 1000); // fade out
$("#box").show("slide", {}, 500); // slide in
$("#box").toggle("explode", {}, 800); // explode toggle
$("#box").effect("bounce", { times: 3 }, 300);
// Available effect names:
// blind, bounce, clip, drop, explode, fade, fold,
// highlight, puff, pulsate, scale, shake, size, slide, transferEasing Functions
jQuery UI's effects core adds ~30 Robert Penner easing functions beyond jQuery's default 'swing' and 'linear'. Use them in any .animate() call, the easing option of show/hide/toggle, or as the third argument. 'easeOutBounce' and 'easeOutElastic' are popular for playful UIs.
// jQuery core provides: swing (default), linear
// jQuery UI adds ~30 more easing functions
$("#box").animate({ width: 500 }, 1000, "easeInOutBounce");
// Available easings (subset):
// easeInQuad, easeOutQuad, easeInOutQuad
// easeInCubic, easeOutCubic, easeInOutCubic
// easeInQuart, easeOutQuart, easeInOutQuart
// easeInExpo, easeOutExpo, easeInOutExpo
// easeInBack, easeOutBack, easeInOutBack
// easeInBounce, easeOutBounce, easeInOutBounce
// easeInElastic, easeOutElastic, easeInOutElasticShow/Hide/Toggle with Effects
Pass an effect name as the first argument to show/hide/toggle to animate. The second argument is an options object (direction, distance, percent, etc. depending on the effect). The third is duration; the fourth is a callback. Effects on hidden elements still work via show().
// show with an effect
$("#box").show("drop", { direction: "left" }, 500);
// hide with an effect
$("#box").hide("puff", {}, 500);
// toggle with an effect
$("#box").toggle("scale", { percent: 0 }, 500);
// With a callback
$("#box").hide("blind", 500, function () {
console.log("Animation complete");
});
// Direction option (where applicable)
$("#box").hide("slide", { direction: "up" });Color Animation
jQuery core can't animate colors — jQuery UI's effects core adds this. backgroundColor, color, and borderColor become animatable. switchClass and toggleClass accept a duration to transition between classes smoothly, interpolating all the changed CSS properties.
// jQuery UI extends animate() to support colors
$("#box").animate({
backgroundColor: "#ff0000",
color: "#ffffff",
borderColor: "#000000",
}, 1000);
// Animate through the theme states
$("#box").animate(
{ backgroundColor: $.Color("#0a0") },
{ duration: 500 }
);
// Toggle class with smooth transitions
$("#box").switchClass("old-class", "new-class", 500);
$("#box").toggleClass("active", 500); // duration = animatedClass Transitions
addClass, removeClass, and toggleClass gain an optional duration argument from jQuery UI — all CSS properties that differ between states animate smoothly. switchClass explicitly transitions between two classes. This is the cleanest way to animate between themed states.
// Add/remove classes with animation
$("#box").addClass("highlight", 500); // animate to new class
$("#box").removeClass("highlight", 500);
$("#box").toggleClass("highlight", 500);
// switchClass: smoothly transition from one class to another
$("#box").switchClass("state-default", "state-active", 500);
// All accept a callback
$("#box").addClass("expanded", 500, function () {
console.log("Done expanding");
});Effect Methods Reference
.effect() applies a named effect without changing visibility (shake, bounce, pulsate are pure effects). .transfer() animates a box outline from one element to another — classic for 'add to cart' feedback. Per-property easing arrays let different properties use different easings.
// .effect() — run an effect without hiding
$("#box").effect("shake", { times: 3 }, 300);
// .transfer() — animate a transfer outline to another element
$("#product").effect("transfer", { to: "#cart" }, 500);
// .animate() with colors and easing
$("#box").animate({ left: 200, opacity: 0.5 }, "slow", "easeOutBounce");
// Custom animation with step
$("#box").animate({
width: ["toggle", "swing"], // [value, easing] per property
height: ["toggle", "linear"],
}, 1000);ThemeRoller
ThemeRoller Basics
ThemeRoller is the official web app for building custom jQuery UI themes. Adjust colors, fonts, corner radius, and textures with live preview, then download a ZIP with the themed CSS and image sprites. Prebuilt themes (smoothness, ui-lightness, etc.) are also available on the CDN.
<!-- Use a prebuilt theme from the CDN -->
<link rel="stylesheet"
href="https://code.jquery.com/ui/1.13.2/themes/smoothness/jquery-ui.css">
<!-- Or a custom theme from ThemeRoller (jqueryui.com/themeroller) -->
<!-- 1. Visit the ThemeRoller app -->
<!-- 2. Customize colors, fonts, corner radius, etc. -->
<!-- 3. Download the generated CSS file -->
<link rel="stylesheet" href="my-custom-theme/jquery-ui.css">CSS Framework Classes
The CSS framework is independent of the JavaScript widgets — use ui-widget, ui-widget-header, ui-widget-content, and the state classes (ui-state-default, ui-state-hover, ui-state-active) in your own markup to match jQuery UI styling without any widget initialization.
<!-- The jQuery UI CSS framework is reusable for custom markup -->
<div class="ui-widget">
<div class="ui-widget-header ui-corner-top">
<h3>Panel Header</h3>
</div>
<div class="ui-widget-content ui-corner-bottom">
<p>Panel content with themed styling.</p>
<button class="ui-button ui-widget ui-state-default ui-corner-all">
<span class="ui-icon ui-icon-gear"></span> Action
</button>
</div>
</div>Theme Variables & Structure
Every theme defines the same set of classes with different colors and textures. ui-state-highlight (yellow) is for notices; ui-state-error (red) for errors. The corner classes (ui-corner-all, ui-corner-top, etc.) make border-radius themable — ThemeRoller sets them all at once.
/* ThemeRoller generates CSS with these key classes */
.ui-widget {
font-family: Arial, sans-serif; /* font family */
font-size: 1em; /* base font size */
}
.ui-widget-content { border: 1px solid #aaa; background: #fff; color: #222; }
.ui-widget-header { border: 1px solid #aaa; background: #ccc; color: #222; }
.ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6; }
.ui-state-hover { border: 1px solid #999; background: #dadada; }
.ui-state-active { border: 1px solid #aaa; background: #fff; }
.ui-state-focus { border: 1px solid #999; background: #dadada; }
.ui-state-highlight { border: 1px solid #fcefa1; background: #fbf9ee; }
.ui-state-error { border: 1px solid #cd0a0a; background: #fef1ec; }
.ui-corner-all { border-radius: 4px; } /* themable radius */Custom Theme Override
Load a base theme then override with higher-specificity CSS. This is faster than re-running ThemeRoller for small tweaks. Target the framework classes (ui-widget-header, ui-state-default, etc.) to restyle all widgets at once. Remove the corner radius for a flat, modern look.
/* Load the base theme first */
@import url("https://code.jquery.com/ui/1.13.2/themes/base/jquery-ui.css");
/* Override specific elements */
.ui-widget-header {
background: linear-gradient(to bottom, #2c3e50, #34495e);
color: #ecf0f1;
}
.ui-state-default {
background: #3498db;
border-color: #2980b9;
color: #fff;
}
.ui-state-hover { background: #2980b9; }
.ui-state-active { background: #1abc9c; border-color: #16a085; }
.ui-corner-all { border-radius: 0; } /* sharper look */Theme Switching at Runtime
To switch themes at runtime, load multiple theme CSS files and toggle their 'disabled' property — only the enabled one applies. Persist the choice in localStorage. The widgets immediately pick up the new styling. For a single-CSS solution, swap the href attribute instead.
<!-- Two theme stylesheets; toggle the disabled attribute -->
<link id="theme-light" rel="stylesheet"
href="themes/ui-lightness/jquery-ui.css">
<link id="theme-dark" rel="stylesheet"
href="themes/ui-darkness/jquery-ui.css" disabled>
<script>
function switchTheme(name) {
$("#theme-light").prop("disabled", name !== "light");
$("#theme-dark").prop("disabled", name !== "dark");
localStorage.setItem("theme", name);
}
// Restore on load
$(function () {
var saved = localStorage.getItem("theme") || "light";
switchTheme(saved);
});
</script>Theming Specific Widgets
Target widget-specific classes (ui-datepicker, ui-dialog, ui-accordion-header) to restyle individual widgets without affecting others. The 1.12+ 'classes' option is cleaner — it adds custom classes to specific internal elements, which you style in your CSS. Use it instead of global overrides when possible.
/* Datepicker: style the calendar popup */
.ui-datepicker {
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
border-radius: 0;
}
.ui-datepicker .ui-state-highlight { /* today */ background: #ffd; }
.ui-datepicker .ui-state-active { /* selected */ background: #2c3e50; }
/* Dialog: remove the default rounded corners */
.ui-dialog { border-radius: 0; box-shadow: 0 8px 30px rgba(0,0,0,0.3); }
/* Accordion: modernize the headers */
.ui-accordion .ui-accordion-header {
background: #f5f5f5;
border: none;
border-bottom: 1px solid #ddd;
font-weight: bold;
}
/* Use the 'classes' option (1.12+) for per-widget theming */
$("#dialog").dialog({
classes: { "ui-dialog": "my-dialog", "ui-dialog-titlebar": "my-title" },
});Related jQuery UI snippets
Copy-paste ready code for common tasks.
Draggable
Make elements draggable with axis, containment, and event callbacks.
Droppable
Create drop targets that accept draggable elements with hover and drop events.
Resizable
Add resize handles with min/max constraints and aspect ratio lock.
Sortable
Reorder list items via drag-and-drop and persist the new order.
Accordion
Collapsible content panels with only one section expanded at a time.
Datepicker
Calendar widget with date range limits, formatting, and inline mode.
Dialog
Modal window with buttons, animations, and dynamic open/close.
Tabs
Tabbed content panels with AJAX loading and event-driven switching.
Was this helpful?