Client-side data storage system for associating arbitrary data with DOM elements safely and efficiently. jQuery's data system provides a clean interface for storing and retrieving data without polluting the DOM or causing memory leaks.
Store and retrieve arbitrary data associated with DOM elements using jQuery's internal data system.
/**
* Store data associated with DOM elements
* @param key - Data key or object of key/value pairs
* @param value - Data value to store
* @returns jQuery object for chaining (when setting) or stored value (when getting)
*/
data(key: string): any;
data(key: string, value: any): jQuery;
data(obj: object): jQuery;
data(): object;
/**
* Remove stored data from elements
* @param key - Optional specific key to remove, or space-separated keys
* @returns jQuery object for chaining
*/
removeData(key?: string): jQuery;Usage Examples:
// Store single value
$('#element').data('user-id', 123);
$('#element').data('preferences', { theme: 'dark', lang: 'en' });
// Store multiple values at once
$('#element').data({
'status': 'active',
'priority': 'high',
'created': new Date()
});
// Retrieve single value
const userId = $('#element').data('user-id'); // 123
const prefs = $('#element').data('preferences'); // { theme: 'dark', lang: 'en' }
// Retrieve all data
const allData = $('#element').data();
console.log(allData); // { user-id: 123, preferences: {...}, status: 'active', ... }
// Remove specific data
$('#element').removeData('user-id');
// Remove multiple keys
$('#element').removeData('status priority');
// Remove all data
$('#element').removeData();
// Data persistence across operations
$('.item').each(function(index) {
$(this).data('index', index);
$(this).data('original-class', this.className);
});
// Later retrieve and use data
$('.item').click(function() {
const index = $(this).data('index');
const originalClass = $(this).data('original-class');
console.log('Item', index, 'clicked, original class:', originalClass);
});Automatic integration with HTML5 data-* attributes with type conversion and camelCase normalization.
// HTML5 data attributes are automatically accessible via .data()
// data-user-name becomes accessible as 'userName' or 'user-name'
// Values are automatically parsed (JSON, numbers, booleans)Usage Examples:
<!-- HTML with data attributes -->
<div id="product"
data-product-id="123"
data-price="29.99"
data-available="true"
data-tags='["electronics", "gadget"]'
data-metadata='{"brand": "TechCo", "model": "X1"}'>
Product Info
</div>// Access data attributes
const productId = $('#product').data('product-id'); // 123 (number)
const productId2 = $('#product').data('productId'); // 123 (camelCase access)
const price = $('#product').data('price'); // 29.99 (number)
const available = $('#product').data('available'); // true (boolean)
const tags = $('#product').data('tags'); // ["electronics", "gadget"] (array)
const metadata = $('#product').data('metadata'); // {brand: "TechCo", model: "X1"} (object)
// Set data attributes (updates both data store and DOM attribute)
$('#product').data('product-id', 456);
// HTML becomes: data-product-id="456"
// Complex data structures
$('#product').data('user-settings', {
notifications: true,
theme: 'dark',
languages: ['en', 'es']
});
// Retrieve all data including HTML5 attributes
const allProductData = $('#product').data();
console.log(allProductData);
// { productId: 123, price: 29.99, available: true, tags: [...], metadata: {...} }Direct data manipulation on DOM elements without jQuery objects.
/**
* Store data directly on DOM element
* @param element - DOM element to store data on
* @param key - Data key or object of key/value pairs
* @param value - Optional data value
* @returns Stored value or undefined
*/
$.data(element: Element, key: string): any;
$.data(element: Element, key: string, value: any): any;
$.data(element: Element, obj: object): any;
/**
* Remove data directly from DOM element
* @param element - DOM element to remove data from
* @param key - Optional specific key to remove
*/
$.removeData(element: Element, key?: string): void;
/**
* Check if DOM element has associated jQuery data
* @param element - DOM element to check
* @returns true if element has data, false otherwise
*/
$.hasData(element: Element): boolean;Usage Examples:
// Direct element data manipulation
const element = document.getElementById('myDiv');
// Store data
$.data(element, 'timestamp', Date.now());
$.data(element, 'config', { active: true, mode: 'edit' });
// Retrieve data
const timestamp = $.data(element, 'timestamp');
const config = $.data(element, 'config');
// Check for data
if ($.hasData(element)) {
console.log('Element has associated data');
}
// Remove data
$.removeData(element, 'timestamp');
$.removeData(element); // Remove all data
// Useful for non-jQuery DOM manipulation
function attachBehavior(element, behavior) {
$.data(element, 'behavior', behavior);
element.addEventListener('click', function() {
const behaviorData = $.data(element, 'behavior');
behaviorData.execute();
});
}
// Clean up data before removing elements
function cleanRemoveElement(element) {
if ($.hasData(element)) {
$.removeData(element);
}
element.parentNode.removeChild(element);
}Store configuration and settings data with elements.
Usage Examples:
// Widget configuration
$('.widget').each(function() {
const $widget = $(this);
const config = {
autoRefresh: $widget.hasClass('auto-refresh'),
refreshInterval: parseInt($widget.attr('data-refresh')) || 5000,
apiEndpoint: $widget.attr('data-api') || '/api/default'
};
$widget.data('config', config);
});
// Use configuration later
$('.widget').on('init', function() {
const config = $(this).data('config');
if (config.autoRefresh) {
setInterval(() => {
refreshWidget(this, config.apiEndpoint);
}, config.refreshInterval);
}
});
// Form field validation rules
$('input[data-validation]').each(function() {
const $input = $(this);
const rules = $input.attr('data-validation').split('|');
$input.data('validation-rules', rules.map(rule => {
const [name, param] = rule.split(':');
return { name, param };
}));
});Track element states and application data.
Usage Examples:
// Track element states
$('.toggle-button').click(function() {
const $btn = $(this);
const isExpanded = $btn.data('expanded') || false;
$btn.data('expanded', !isExpanded);
$btn.attr('aria-expanded', !isExpanded);
$btn.toggleClass('expanded', !isExpanded);
if (!isExpanded) {
$btn.next('.collapsible').slideDown();
} else {
$btn.next('.collapsible').slideUp();
}
});
// Form interaction tracking
$('form input, form select, form textarea').on('change', function() {
const $form = $(this).closest('form');
let changeCount = $form.data('change-count') || 0;
$form.data('change-count', ++changeCount);
if (changeCount === 1) {
$form.data('original-state', $form.serialize());
}
$form.toggleClass('modified', changeCount > 0);
});
// Check for unsaved changes
$(window).on('beforeunload', function() {
let hasChanges = false;
$('form.modified').each(function() {
if ($(this).data('change-count') > 0) {
hasChanges = true;
return false;
}
});
if (hasChanges) {
return 'You have unsaved changes. Are you sure you want to leave?';
}
});Cache expensive computations and API responses.
Usage Examples:
// Cache computed values
function getElementDimensions($element) {
let dimensions = $element.data('cached-dimensions');
if (!dimensions) {
dimensions = {
width: $element.width(),
height: $element.height(),
offset: $element.offset(),
computed: Date.now()
};
$element.data('cached-dimensions', dimensions);
}
return dimensions;
}
// Cache API responses
function loadUserData(userId) {
const $userContainer = $('#user-' + userId);
let userData = $userContainer.data('user-data');
if (!userData) {
return $.get('/api/users/' + userId).done(function(data) {
$userContainer.data('user-data', {
...data,
cached: Date.now()
});
return data;
});
}
// Return cached data as resolved promise
return $.Deferred().resolve(userData).promise();
}
// Cache invalidation
function invalidateUserCache(userId) {
$('#user-' + userId).removeData('user-data');
}
// Lazy loading with data caching
$('.lazy-load').on('inview', function() {
const $element = $(this);
if ($element.data('loaded')) return;
const url = $element.data('src');
$element.load(url, function() {
$element.data('loaded', true);
$element.data('load-time', Date.now());
});
});Implement data binding patterns for interactive components.
Usage Examples:
// Simple data binding
function bindData($element, data) {
$element.data('bound-data', data);
// Update display
updateDisplay($element);
// Set up watchers
$element.on('data-change', function(e, key, newValue) {
const boundData = $element.data('bound-data');
boundData[key] = newValue;
updateDisplay($element);
});
}
function updateDisplay($element) {
const data = $element.data('bound-data');
$element.find('[data-bind]').each(function() {
const key = $(this).attr('data-bind');
if (data.hasOwnProperty(key)) {
$(this).text(data[key]);
}
});
}
// Usage
const userData = { name: 'John Doe', email: 'john@example.com' };
bindData($('#user-profile'), userData);
// Trigger data change
$('#name-input').on('input', function() {
const newName = $(this).val();
$('#user-profile').trigger('data-change', ['name', newName]);
});
// Component factory with data storage
function createCounter($element, initialValue = 0) {
$element.data('counter-value', initialValue);
$element.html(`
<button class="decrement">-</button>
<span class="value">${initialValue}</span>
<button class="increment">+</button>
`);
$element.on('click', '.increment', function() {
let value = $element.data('counter-value');
$element.data('counter-value', ++value);
$element.find('.value').text(value);
$element.trigger('counter:change', [value]);
});
$element.on('click', '.decrement', function() {
let value = $element.data('counter-value');
$element.data('counter-value', --value);
$element.find('.value').text(value);
$element.trigger('counter:change', [value]);
});
return $element;
}
// Create counter components
createCounter($('#counter1'), 5);
createCounter($('#counter2'), 10);jQuery's data system automatically handles memory cleanup, but understanding the patterns helps optimize performance.
Usage Examples:
// Automatic cleanup when elements are removed via jQuery
$('#temporary-element').data('large-object', { /* large data */ });
$('#temporary-element').remove(); // Data is automatically cleaned up
// Manual cleanup for better control
function cleanupComponent($component) {
// Clear timers stored in data
const timers = $component.data('timers') || [];
timers.forEach(clearInterval);
// Clear event handlers
$component.off('.component');
// Remove all data
$component.removeData();
}
// Efficient data sharing between elements
const sharedConfig = { theme: 'dark', locale: 'en' };
$('.component').data('shared-config', sharedConfig); // Same object reference
// Avoid storing DOM elements in data to prevent circular references
// Instead of:
// $element.data('related-element', $otherElement);
// Use:
$element.data('related-element-id', $otherElement.attr('id'));