Methods
(static) decodeFragment(hash) → {string}
The id a #fragment names - out of an href or out of location.hash, both of
which arrive with the # still on.
Decoded, because id="café" is reached by href="#caf%C3%A9" and the two have to
meet somewhere. Taken as written when decoding fails: a stray % in a fragment is a
typo, and a typo in one link is not a reason for the caller to stop working.
- Source:
Parameters:
| Name | Type | Description |
|---|---|---|
hash |
string
|
The fragment, with or without the leading |
Returns:
- Type:
-
string
The decoded id, '' for an empty fragment
Example
decodeFragment('#caf%C3%A9') // => 'café'
decodeFragment(window.location.hash) // => the id the url points at
decodeFragment('#100%') // => '100%', kept as written
(static) disableScroll(shiftopt)
Disable the scroll on the page.
- Source:
Parameters:
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
shift |
number
|
<optional> |
0 |
If greater than 0 the body will be shifted to the left by the width of the scrollbar, getScrollbarWidth() is used to provide this value |
(static) enableScroll(shiftopt)
Enable the scroll on the page.
- Source:
Parameters:
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
shift |
boolean
|
<optional> |
0 |
If greater than 0 the body will be shifted back to the left by the width of the scrollbar, getScrollbarWidth() is used to provide this value |
(static) getHashProperties(entryHashopt) → {object}
Parses a string of url hash parameters into an object of key value pairs. Converts the values to the correct type.
- Source:
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
entryHash |
string
|
<optional> |
Optional hash string to parse, without the starting #, defaults to window.location.hash without the starting # |
Returns:
- Type:
-
object
of key value pairs
Example
// url: https://example.com/#test&foo=bar&baz=qux
getHashProperties() // { test: undefined, foo: 'bar', baz: 'qux' }
(static) getQueryProperties(entryQueryopt) → {object}
Parses a string of url query parameters into an object of key value pairs. Converts the values to the correct type.
- Source:
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
entryQuery |
string
|
<optional> |
Optional query string to parse, without the starting ?, defaults to window.location.search without the starting ? |
Returns:
- Type:
-
object
of key value pairs
Example
// url: https://example.com/?test&foo=bar&baz=qux
getQueryProperties() // { test: undefined, foo: 'bar', baz: 'qux' }
(static) getScrollbarWidth() → {number}
Get the scrollbar width
When preventing scroll with html overflow hidden the scroll bar will disappear and the whole page will shift (if the scroll bar is visible that is). To substitute for the scrollbar width we can add a padding to the body element.
- Source:
Returns:
- Type:
-
number
The scrollbar width
Example
const scrollbarWidth = getScrollbarWidth() // 15 (on MacOS X Safari)
(static) hasHorizontalScrollbarVisible(scrollbarWidthopt) → {boolean}
Check if the horizontal scrollbar is visible
- Source:
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
scrollbarWidth |
number
|
<optional> |
The width of the scrollbar, defaults to getScrollbarWidth() |
Returns:
- Type:
-
boolean
True if the horizontal scrollbar is visible, false otherwise
(static) hasVerticalScrollbarVisible(scrollbarWidthopt) → {boolean}
Check if the vertical scrollbar is visible
- Source:
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
scrollbarWidth |
number
|
<optional> |
The width of the scrollbar, defaults to getScrollbarWidth() |
Returns:
- Type:
-
boolean
True if the vertical scrollbar is visible, false otherwise
(static) hashChange(callback, singleopt)
Add a callback function to the hash change event
- Source:
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
callback |
function
|
The callback function to call when the hash changes |
|
single |
string
|
<optional> |
Optional string to make sure the listener is initialized only once, defaults to window[single] which is set to true after the first call |
Example
hashChange((hash) => {
// Do something with the hash
})
(static) isIOS()
Check if the device is an iOS device
- Source:
Returns:
boolean True if the device is an iOS device, false otherwise
(static) isIOSSafari()
Check if the browser is Safari on iOS
- Source:
Returns:
boolean True if the browser is Safari on iOS, false otherwise
(static) isMobile()
Check if the device is a mobile device
- Source:
Returns:
boolean True if the device is a mobile device, false otherwise
(static) isSafari()
Check if the browser is Safari
- Source:
Returns:
boolean True if the browser is Safari, false otherwise
(static) mediaMatcher(query, callbackopt) → {boolean}
A wrapper for the matchMedia function, cause with matchMedia you can only either add a listener or check the media query
this function does both.
- Source:
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
query |
string
|
The media query to check |
|
callback |
function
|
<optional> |
The callback function to call when the media query changes |
Returns:
- Type:
-
boolean
The result of the media query
Example
mediaMatcher('(min-width: 768px)', (matches) => {
if (matches) {
// Do something
} else {
// Do something else
}
})
// Or
const isDesktop = mediaMatcher('(min-width: 768px)')
(static) prefersReducedMotion(callbackopt) → {boolean}
Checks whether the user has asked the system to minimize non-essential motion.
Animations should be skipped or reduced when this is true - it is an accessibility
setting, not a preference, and for some users motion causes nausea or worse.
Returns false where matchMedia does not exist, so it is safe to call outside a
browser: no preference expressed, no motion suppressed.
- Source:
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
callback |
function
|
<optional> |
The callback function to call when the preference changes |
Returns:
- Type:
-
boolean
True if the user prefers reduced motion
Example
if (prefersReducedMotion()) duration = 0
// Or, to react to the user changing it while the page is open
prefersReducedMotion((reduced) => {
document.body.classList.toggle('is-still', reduced)
})
(static) userActivity(callback, optionsopt) → {object|null}
Reports when the user has stopped interacting with the page, and when they come back.
Idle means no interaction for timeout milliseconds — the callback gets false once that
runs out and true the moment the user comes back, so a video can pause itself, a poll can
stop polling, or a session can end where it should. Only the changes are reported: a reader
scrolling steadily gets one true at the end of their pause, not one per event, and the page
starting out active is not reported at all, being the state every caller already has.
There is a native IdleDetector, but it is Chromium-only, needs the idle-detection
permission, and answers a different question — whether the machine is idle or its screen
locked, not whether anyone is reading this page.
What the clock says outranks what the timer says. A timer set for the idle deadline can run
late: a long task blocks it, a background tab has its timers clamped to a second, and a tab
the browser has frozen may not run it at all. Waking late is therefore treated as proof the
user is idle rather than as a reason to doubt it, waking early re-arms for the remainder, and
a tab returning from hidden checks its deadline at once, since nothing may have run while it
was away. The clock is performance.now() — the wall clock jumps on an NTP correction or a
daylight-saving change, and would take the deadline with it.
Answers for this tab alone unless channel is given a name, in which case every tab of this
origin using that name agrees: activity in any of them counts in all of them, and idle means
all of them are. That is what a session deadline wants — three tabs open and work happening
in the third should not log the first two out — and what a pausing video does not, since a
user reading elsewhere is exactly when this tab should stop playing. Hence a name to opt in
rather than a default. Where BroadcastChannel is missing, each tab falls back to answering
for itself.
- Source:
Parameters:
| Name | Type | Attributes | Description | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
callback |
function
|
Called with |
|||||||||||||||||||||
options |
object
|
<optional> |
|
Returns:
- Type:
-
object|null
{ destroy }, or null when there is no callback, no DOM, no positive timeout, or no events to listen for
Example
const activity = userActivity((active) => {
if (!active) video.pause()
}, { timeout: 30000 })
activity.destroy() // stop listening
// Warning someone before the deadline is two observers, not an extra option
userActivity((active) => { warning.hidden = active }, { timeout: 25 * 60000 })
userActivity((active) => { if (!active) logout() }, { timeout: 30 * 60000 })
// A deadline the whole site agrees on, however many tabs are open
userActivity((active) => { if (!active) logout() }, { timeout: 15 * 60000, channel: 'session' })