jQuery.cssHooks lets you plug custom logic into how jQuery reads and writes CSS properties. This tutorial covers the get/set hook shape, vendor-prefix normalization, $.cssNumber, animation via $.fx.step, feature testing, and official jQuery patterns from the API docs.
01
Object
$.cssHooks
02
get
Read handler
03
set
Write handler
04
cssNumber
Skip auto px
05
fx.step
Animate hook
06
Since 1.4.3
Extension API
Fundamentals
Introduction
Most of the time, .css() reads computed styles and writes inline properties without you thinking about browser quirks. Plugin authors and advanced developers sometimes need more control — mapping -webkit-border-radius to a single borderRadius name, reading rotation from a transform string, or teaching .animate() to tween a property jQuery does not know natively.
Available since jQuery 1.4.3, jQuery.cssHooks is the extension point behind that flexibility. jQuery ships built-in hooks for properties like opacity and scrollTop. You add entries keyed by camelCase property names; each entry may define get and set functions that jQuery calls whenever code uses .css() or .animate() on that property.
Concept
Understanding jQuery.cssHooks
jQuery.cssHooks is a plain object on the jQuery namespace. Keys are CSS property names in camelCase (for example borderRadius, scrollTop). Values are objects with optional get and set functions. When matched elements call .css("borderRadius"), jQuery looks up $.cssHooks.borderRadius.get if it exists; when setting, it calls set.
Think of cssHooks as adapters between jQuery’s uniform API and whatever the browser needs under the hood. Your hook receives the raw DOM element and the value; you decide how to read or write it. Once registered, callers use the normal .css() syntax — hyphenated (border-radius) or camelCase (borderRadius) — and jQuery routes through your adapter.
💡
Beginner Tip
You do not need cssHooks for everyday styling. Reach for them when you are building a jQuery plugin, normalizing legacy vendor prefixes, or exposing a custom animatable property that plain element.style cannot express directly.
Foundation
📝 Syntax
A cssHook is registered by assigning an object to a property name on $.cssHooks:
Hook skeleton (official jQuery template)
jQuery
(function( $ ) {
if ( !$.cssHooks ) {
throw new Error( "jQuery 1.4.3+ is required" );
}
$(function () {
$.cssHooks.someCSSProp = {
get: function( elem, computed, extra ) {
// return current value (String or Number)
},
set: function( elem, value ) {
// write value to elem
}
};
});
})( jQuery );
get(elem, computed, extra) — called when reading .css("someCSSProp"). Return the value jQuery should expose.
set(elem, value) — called when writing .css("someCSSProp", value). Apply the value to the element.
Register inside $(function(){ ... }) so jQuery does not overwrite your hook during its own initialization.
Feature test helper (styleSupport)
jQuery
function styleSupport( prop ) {
var capProp = prop.charAt( 0 ).toUpperCase() + prop.slice( 1 ),
prefixes = [ "Moz", "Webkit", "ms" ],
div = document.createElement( "div" ),
supportedProp;
if ( prop in div.style ) {
supportedProp = prop;
} else {
for ( var i = 0; i < prefixes.length; i++ ) {
var vendorProp = prefixes[ i ] + capProp;
if ( vendorProp in div.style ) {
supportedProp = vendorProp;
break;
}
}
}
div = null;
$.support[ prop ] = supportedProp;
return supportedProp;
}
Tests standard name first, then vendor-prefixed variants (WebkitBorderRadius, etc.).
Stores result on $.support[prop] for reuse inside your hook.
Unitless numbers — $.cssNumber
jQuery
$.cssNumber.someCSSProp = true;
By default jQuery appends px to numeric setter values for dimension properties.
Set $.cssNumber.propName = true to keep numbers unitless (opacity, z-index, custom degrees, etc.).
Box corners round to 16px
.css("borderRadius") reads back "16px"
Hook registered inside $(function(){ ... })
How It Works
The official skeleton wraps registration in document ready. get delegates to jQuery’s CSS reader; set writes directly to elem.style. Callers still use familiar .css() syntax.
Example 2 — Official Demo: Feature Test with styleSupport
Detect which border-radius property name the browser supports before registering a hook.
jQuery
function styleSupport( prop ) {
var capProp = prop.charAt( 0 ).toUpperCase() + prop.slice( 1 ),
prefixes = [ "Moz", "Webkit", "ms" ],
div = document.createElement( "div" ),
supportedProp;
if ( prop in div.style ) {
supportedProp = prop;
} else {
for ( var i = 0; i < prefixes.length; i++ ) {
var vendorProp = prefixes[ i ] + capProp;
if ( vendorProp in div.style ) {
supportedProp = vendorProp;
break;
}
}
}
div = null;
$.support[ prop ] = supportedProp;
return supportedProp;
}
styleSupport( "borderRadius" );
Modern browser → "borderRadius"
Legacy WebKit → "WebkitBorderRadius"
Stored on $.support.borderRadius
How It Works
Before normalizing vendor prefixes, detect support once. Store the winning property name on $.support so your hook’s get/set functions can reuse it without re-testing every call.
📈 Normalization & Animation
Complete hooks, unitless numbers, and tweening.
Example 3 — Official Demo: Complete borderRadius Hook
Combine feature testing with get/set so both hyphenated and camelCase names work.
Box A → 10px radius via borderRadius
Box B → 20px radius via border-radius
Same hook handles both naming styles
How It Works
The official complete hook reads and writes through the detected property name. If the browser lacks any form of the property, skip registration — the style is not applied rather than throwing an error.
Example 4 — Special Units with $.cssNumber
Expose a custom rotateDeg property that stores degrees without jQuery appending px.
By default jQuery treats numeric setters as pixel dimensions. $.cssNumber.rotateDeg = true marks the property as unitless so 45 stays 45, not 45px. The hook maps that number to a transform: rotate(Ndeg) string.
Example 5 — Animating with cssHooks and $.fx.step
Click to tween borderRadius — cssHooks extend .animate() when combined with an fx step.
Click box → borderRadius animates 0 → 40px over 600ms
Click again → animates back to square
fx.step pushes each frame through cssHooks.set
How It Works
cssHooks tell jQuery how to read and write a property; $.fx.step tells the animation engine how to apply intermediate numeric values each frame. Together they make custom properties animatable with familiar .animate() syntax.
Applications
🚀 Common Use Cases
Vendor-prefix normalization — map -webkit-border-radius and -moz-border-radius to one borderRadius hook.
Plugin development — ship a jQuery plugin that adds animatable custom properties without patching core.
Transform helpers — expose rotateDeg or scaleX as simple numeric cssHook properties.
Legacy browser support — feature-test once, store on $.support, branch inside get/set.
Scroll and opacity — study built-in hooks like scrollTop and opacity jQuery already registers.
Custom tweening — combine cssHooks with $.fx.step for smooth numeric animations.
🧠 How cssHooks Plug Into jQuery
1
Register hook
Assign { get, set } to $.cssHooks.propName inside document ready.
Setup
2
Caller uses .css()
.css("propName") or .css("propName", value) — same public API.
API
3
jQuery routes
If a hook exists, jQuery calls your get or set instead of default logic.
Dispatch
4
🎨
Animate optionally
.animate({ propName: n }) reuses the same hook; add $.fx.step if needed.
Important
📝 Notes
Available since jQuery 1.4.3 — requires $.cssHooks to exist before registering.
Register hooks inside $(function(){ ... }) — jQuery initializes its own hooks at document ready.
Property keys use camelCase DOM names (borderRadius, not border-radius).
Hyphenated names still work at call sites — jQuery normalizes them to the hook key.
$.cssNumber.prop = true prevents automatic px suffix on numeric setters.
Built-in hooks include opacity, scrollTop, and scrollLeft — inspect $.cssHooks in DevTools.
If feature test finds no supported property, skip hook registration — do not throw unless your plugin requires it.
Compatibility
Browser Support
jQuery.cssHooks has been part of jQuery since 1.4.3+. Hooks run in whatever browser loads jQuery — your hook’s get/set logic must handle vendor differences via feature tests. Modern evergreen browsers rarely need prefix hooks for common CSS3 properties.
✓ jQuery 1.4.3+
jQuery.cssHooks
Supported in jQuery 1.x, 2.x, and 3.x. cssHooks are a jQuery extension API, not a native browser feature — behavior depends on the get/set functions you write and the browsers you target.
100%With jQuery loaded
Google ChromeAll versions · Desktop & Mobile
Full support
Mozilla FirefoxAll versions · Desktop & Mobile
Full support
Apple SafariAll versions · macOS & iOS
Full support
Microsoft EdgeAll versions · Chromium & Legacy
Full support
Internet ExplorerIE 6+ · Legacy environments
Full support
OperaAll modern versions
Full support
cssHooksUniversal
Bottom line: Safe in any jQuery 1.4.3+ project. Feature-test CSS properties inside your hook for legacy prefix support.
Wrap Up
Conclusion
jQuery.cssHooks is the extension point behind .css() and .animate(). Register get and set handlers on camelCase property names to normalize vendor prefixes, expose custom properties, and enable tweening.
Remember the official workflow: feature-test with styleSupport(), register inside document ready, use $.cssNumber for unitless values, and add $.fx.step when animations need per-frame help. For everyday styling, stick with .css() — cssHooks are for plugins and advanced cases.
Feature-test CSS properties once and cache on $.support
Use $.cssNumber for unitless numeric properties
Keep get/set functions small and focused on one property
Document custom property names if you expose them in a plugin
❌ Don’t
Register cssHooks for properties that work fine with plain .css()
Assign hooks before jQuery finishes its own cssHooks setup
Assume vendor-prefix hooks are still needed for modern CSS3 in 2026
Forget to skip registration when the browser lacks support
Mix multiple transform operations without reading the existing transform string
Summary
Key Takeaways
Knowledge Unlocked
Six things to remember about cssHooks
Extend .css() — power .animate().
6
Core concepts
{ }01
Object
$.cssHooks
Registry
?02
get
Read
Getter
=03
set
Write
Setter
#04
cssNumber
No px
Units
~05
fx.step
Tween
Animate
✓06
ready
Timing
Safe
❓ Frequently Asked Questions
jQuery.cssHooks is an object on the jQuery namespace where you register get and set handlers for CSS property names. When you call .css('propertyName') or .animate({ propertyName: value }), jQuery routes through your hook instead of using the default inline-style logic — useful for vendor prefixes, computed transforms, and custom properties.
Use cssHooks when a CSS property needs special handling: mapping -webkit-border-radius to borderRadius, reading rotation from a transform string, or exposing a synthetic property that does not map 1:1 to element.style. For everyday color and width changes, plain .css() is enough. cssHooks are for plugin authors and advanced styling extensions.
jQuery initializes its own built-in cssHooks during document ready. If you assign $.cssHooks.myProp before that finishes, jQuery may overwrite your object. The official docs recommend wrapping registration in a document-ready callback so your get/set functions persist.
cssHooks define how to read and write a property. cssNumber is a separate lookup: when true for a property name, jQuery skips auto-appending 'px' to numeric setter values. Use cssNumber for unitless numbers like opacity, z-index, or a custom degree value in your hook.
Once a property has a cssHook with get and set, jQuery's animation engine can tween it. For simple numeric properties you may only need the hook. For complex values, add $.fx.step.propertyName to push intermediate values through your setter during each animation frame.
Rarely for common properties — modern browsers support standard border-radius, transform, and flex names. cssHooks remain valuable for understanding jQuery internals, maintaining legacy plugins, animating non-standard properties, and teaching how .css() and .animate() share one extension point.
Did you know?
jQuery uses cssHooks internally for properties that do not map cleanly to inline styles — scrollTop, scrollLeft, and opacity are built-in examples you can inspect on $.cssHooks in the console. The same mechanism that powered vendor-prefixed border-radius in 2010 now lets plugin authors expose synthetic properties like rotation degrees while keeping the familiar .css() and .animate() API.