This spec requires large amounts of work to section it and word it in ways that are normative. It is currently a very rough draft.
1. Introduction
This section is non-normative.
Currently, website authors have a choice when wishing to honour a user’s preference for a given setting:
They can choose to "use the platform" where the user must indicate their preference via their OS or, if lucky, they can override in the browser. This comes with a number of issues:
-
Relies on the user’s OS or browser offering the ability to change the setting
-
Relies on the user knowing how to change the setting in their OS or browser
-
No ability to override the setting for a specific site
-
No ability to sync preferences for a site across devices
Alternatively, sites can and do offer site-level settings, but this currently comes with a number of issues:
-
No integration with Media Queries 5 § 11. User Preference Media Features
-
No integration with conditional resource loading (e.g. using
media="(prefers-contrast: more)"
on asource
element) -
No integration with JS APIs for retrieval of these preferences (e.g.
matchMedia
in CSSOM View § 4 Extensions to the Window Interface -
No integration with [USER-PREFERENCE-MEDIA-FEATURES-HEADERS]
-
No integration with the CSS Color Adjustment 1 § 2 Preferred Color Schemes concept
-
The various client storage mechanisms that could store these preferences can be cleared in a number of scenarios
Unsure how to link to html spec for the source media attribute example.
The Web Preferences API aims to solve this by providing a way for sites to override the value for a given a user preference.
It is intended for this override to apply permanently and be scoped per origin. The override should be passed down to sub-resource where possible, see privacy section for details. This explainer refers to "site" but it should be read to mean origin.
2. Extensions to the Navigator
interface
[Exposed =Window ,SecureContext ]partial interface Navigator { [SameObject ]readonly attribute PreferenceManager ; };
preferences
2.1. preferences
attribute
When getting the preferences
attribute always return the same instance of the PreferenceManager
object.
3. PreferenceManager
interface
[Exposed =Window ,SecureContext ]interface {
PreferenceManager readonly attribute PreferenceObject ;
colorScheme readonly attribute PreferenceObject ;
contrast readonly attribute PreferenceObject ;
reducedMotion readonly attribute PreferenceObject ;
reducedTransparency readonly attribute PreferenceObject ; };
reducedData
Note: The exact set of preferences is down to the browser vendor, but it is expected that the set of preferences will be the same as those defined in [mediaqueries-5].
3.1. colorScheme
attribute
The colorScheme
attribute is a PreferenceObject
used to override the user’s preference for the color scheme of the site.
This is modeled after the prefers-color-scheme
user preference media feature as defined in Media Queries 5 § 11.5 Detecting the desire for light or dark color schemes: the prefers-color-scheme feature.
-
Let validValues be a new empty sequence.
-
Add
"light"
to validValues. -
Add
"dark"
to validValues. -
Return validValues.
If an override is set for this preference:
-
The user agent MUST use this override for the Media Queries 5 § 11.5 Detecting the desire for light or dark color schemes: the prefers-color-scheme feature in all stylesheets applied to an origin including the UA style sheet.
-
The user agent MUST also use this override when queried via
matchMedia()
from CSSOM View § 4 Extensions to the Window Interface. -
The user agent MUST also use this override when calculating the used color scheme.
-
The user agent MUST also use this override when sending User Preference Media Features Client Hints Headers § 2.5 Sec-CH-Prefers-Color-Scheme.
-
The user agent MUST also use this override for any UA features that are normally affected by Media Queries 5 § 11.5 Detecting the desire for light or dark color schemes: the prefers-color-scheme feature.
How does this work with forced-colors
or forced dark mode features?
3.2. contrast
attribute
The contrast
attribute is a PreferenceObject
used to override the user’s preference for the contrast of the site.
This is modeled after the prefers-contrast
user preference media feature as defined in Media Queries 5 § 11.3 Detecting the desire for increased or decreased color contrast from elements on the page: the prefers-contrast feature.
-
Let validValues be a new empty sequence.
-
Add
"more"
to validValues. -
Add
"less"
to validValues. -
Add
"no-preference"
to validValues. -
Return validValues.
If an override is set for this preference:
-
The user agent MUST use this override for the Media Queries 5 § 11.3 Detecting the desire for increased or decreased color contrast from elements on the page: the prefers-contrast feature in all stylesheets applied to an origin including the UA style sheet.
-
The user agent MUST also use this override when queried via
matchMedia()
from CSSOM View § 4 Extensions to the Window Interface. -
The user agent MUST also use this override when sending User Preference Media Features Client Hints Headers § 2.3 Sec-CH-Prefers-Contrast.
-
The user agent MUST also use this override for any UA features that are normally affected by Media Queries 5 § 11.3 Detecting the desire for increased or decreased color contrast from elements on the page: the prefers-contrast feature.
Note: Unlike the media feature this preference is NOT able to be set to custom
as this is tightly coupled to the forced-colors
media feature.
3.3. reducedMotion
attribute
The reducedMotion
attribute is a PreferenceObject
used to override the user’s preference for reduced motion on the site.
This is modeled after the prefers-reduced-motion
user preference media feature as defined in Media Queries 5 § 11.1 Detecting the desire for less motion on the page: the prefers-reduced-motion feature.
-
Let validValues be a new empty sequence.
-
Add
"reduce"
to validValues. -
Add
"no-preference"
to validValues. -
Return validValues.
If an override is set for this preference:
-
The user agent MUST use this override for the Media Queries 5 § 11.1 Detecting the desire for less motion on the page: the prefers-reduced-motion feature in all stylesheets applied to an origin including the UA style sheet.
-
The user agent MUST also use this override when queried via
matchMedia()
from CSSOM View § 4 Extensions to the Window Interface. -
The user agent MUST also use this override when sending User Preference Media Features Client Hints Headers § 2.1 Sec-CH-Prefers-Reduced-Motion.
-
The user agent MUST also use this override for any UA features that are normally affected by Media Queries 5 § 11.1 Detecting the desire for less motion on the page: the prefers-reduced-motion feature.
Note: An example of a UA feature that is affected by this preference could be disabling smooth scrolling, or pausing marquee elements.
3.4. reducedTransparency
attribute
The reducedTransparency
attribute is a PreferenceObject
used to override the user’s preference for reduced transparency on the site.
This is modeled after the prefers-reduced-transparency
user preference media feature as defined in Media Queries 5 § 11.2 Detecting the desire for reduced transparency on the page: the prefers-reduced-transparency feature.
-
Let validValues be a new empty sequence.
-
Add
"reduce"
to validValues. -
Add
"no-preference"
to validValues. -
Return validValues.
If an override is set for this preference:
-
The user agent MUST use this override for the Media Queries 5 § 11.2 Detecting the desire for reduced transparency on the page: the prefers-reduced-transparency feature in all stylesheets applied to an origin including the UA style sheet.
-
The user agent MUST also use this override when queried via
matchMedia()
from CSSOM View § 4 Extensions to the Window Interface. -
The user agent MUST also use this override when sending User Preference Media Features Client Hints Headers § 2.2 Sec-CH-Prefers-Reduced-Transparency.
-
The user agent MUST also use this override for any UA features that are normally affected by Media Queries 5 § 11.2 Detecting the desire for reduced transparency on the page: the prefers-reduced-transparency feature.
3.5. reducedData
attribute
The reducedData
attribute is a PreferenceObject
used to override the user’s preference for reduced data usage on the site.
This is modeled after the prefers-reduced-data
user preference media feature as defined in Media Queries 5 § 11.6 Detecting the desire for reduced data usage when loading a page: the prefers-reduced-data feature.
-
Let validValues be a new empty sequence.
-
Add
"reduce"
to validValues. -
Add
"no-preference"
to validValues. -
Return validValues.
If an override is set for this preference:
-
The user agent MUST use this override for the Media Queries 5 § 11.6 Detecting the desire for reduced data usage when loading a page: the prefers-reduced-data feature in all stylesheets applied to an origin including the UA style sheet.
-
The user agent MUST also use this override when queried via
matchMedia()
from CSSOM View § 4 Extensions to the Window Interface. -
The user agent MUST also use this override when sending Save Data API § 2.1.1 Save-Data Request Header Field.
-
The user agent MUST also use this override when calculating the Save Data API § 2.1 saveData attribute.
-
The user agent MUST also use this override for any UA features that are normally affected by Media Queries 5 § 11.6 Detecting the desire for reduced data usage when loading a page: the prefers-reduced-data feature.
3.6. PreferenceObject
interface
[Exposed =Window ,SecureContext ]interface :
PreferenceObject EventTarget {readonly attribute DOMString ?override ;readonly attribute DOMString value ;readonly attribute FrozenArray <DOMString >validValues ;undefined clearOverride ();Promise <undefined >requestOverride (DOMString ?);
value attribute EventHandler onchange ; };
3.6.1. override
attribute
override
attribute, when accessed, must run these steps:
-
Let preference be the preference object’s name.
-
Let override be null.
-
If an override for preference exists, set override to the value of that override.
-
Return override.
3.6.2. value
attribute
value
attribute, when accessed, must run these steps:
-
Let preference be the preference object’s name.
-
Let value be null.
-
If an override for preference exists, set value to the value of that override.
-
If value is null, set value to the UA value of the preference.
-
Return value.
3.6.3. validValues
attribute
validValues
attribute, when accessed, must run these steps:
-
Let preference be the preference object’s name.
-
Let validValues be a new empty sequence.
-
If preference is "
colorScheme
", set validValues to the result of get valid values for colorScheme. -
If preference is "
contrast
", set validValues to the result of get valid values for contrast. -
If preference is "
reducedMotion
", set validValues to the result of get valid values for reducedMotion. -
If preference is "
reducedTransparency
", set validValues to the result of get valid values for reducedTransparency. -
If preference is "
reducedData
", set validValues to the result of get valid values for reducedData. -
Return validValues.
3.6.4. onchange
event handler attribute
The onchange
attribute is an event handler IDL attribute for
the onchange
event handler, whose event handler event type is change.
PreferenceObject
instance value has changed, it asynchronously runs the PreferenceObject
update steps:
-
Let preference be the
PreferenceObject
object that value is associated with. -
If this's relevant global object is a
Window
object, then:-
Let document be preference’s relevant global object's associated Document.
-
If document is null or document is not fully active, terminate this algorithm.
-
-
fire an event named
change
at preference.
3.6.5. requestOverride()
method
requestOverride(value)
method, when invoked, must run these steps:
-
Let result be a new promise.
-
Let allowed be
false
. -
Set allowed to the result of executing a UA defined algorithm for deciding whether the request is allowed.
-
If allowed is
false
, return a promise rejected with a "NotAllowedError
"DOMException
. -
Let value be the method’s argument.
-
Let result be a new promise.
-
If value is
null
or an empty string:-
Run
clearOverride
. -
Resolve and return result.
-
-
Let currentValue be the preference object’s value.
-
Let validValues be null.
-
If preference is "
colorScheme
", set validValues to the result of get valid values for colorScheme. -
If preference is "
contrast
", set validValues to the result of get valid values for contrast. -
If preference is "
reducedMotion
", set validValues to the result of get valid values for reducedMotion. -
If preference is "
reducedTransparency
", set validValues to the result of get valid values for reducedTransparency. -
If preference is "
reducedData
", set validValues to the result of get valid values for reducedData. -
If value is not in validValues:
-
Reject result with a "
TypeError
"DOMException
. -
Return result.
-
-
Let previousOverride be null.
-
If an override for preference exists, set previousOverride to the value of that override.
-
If value is different from previousOverride:
-
Set the preference override for preference to value.
-
-
If previousOverride is null, then:
-
If value is the same as currentValue, then:
-
Fire an event named
change
at this.
-
-
-
Resolve and return result.
This algorithm needs more detail on what exactly setting the preference override does.
Note: The change
event is fired when the computed value changes, but when a new override is set it is also fired if the value hasn’t changed.
3.6.6. clearOverride
method
clearOverride()
method, when invoked, must run these steps:
-
Let preference be the preference object’s name.
-
Let override be null.
-
If an override for preference exists, set override to the value of that override.
-
If override is null, then return.
-
Clear the override for preference.
-
Let newValue be the preference object’s value.
-
If newValue is equal to override, then:
-
Fire an event named
change
at this.
Note: The change
event is fired when the computed value changes, but when an override is cleared it is also fired if the value hasn’t changed.
3.6.7. Garbage Collection
A PreferenceObject
object MUST NOT be garbage collected if it has an event listener whose type is change
.
4. Usage Examples
This section is non-normative.
Each preference the browser supports will be exposed as a property on the navigator.preferences
object.
Feature detection for a given preference is as simple as:
const colorSchemeSupported= 'colorScheme' in navigator. preferences;
4.1. Requesting a preference override
To request a preference override, the requestOverride
method can be called.
navigator. preferences. colorScheme. requestOverride( 'dark' ) . then(() => { // The preference override was successful. }) . catch (( error) => { // The preference override request was rejected. });
4.2. Clearing a preference override
To clear an override and return the preference to the browser default, the clearOverride
method can be called.
navigator. preferences. colorScheme. clearOverride();
4.3. Getting a preference override
To get the value of a preference override, the override
property can be read.
Each preference property’s override property will return the string value indicating the preference, or null if no override is set.
const colorScheme= navigator. preferences. colorScheme. override; // "light" | "dark" | null
4.4. Getting valid values for a preference
Each PreferenceObject
contains a validValues attribute that can be used to determine the valid values for a preference.
This is useful for sites that want to dynamically generate UI for overriding preferences.
It also allows sites to determine if a preference value is supported before attempting to set it.
const validValues= navigator. preferences. colorScheme. validValues; // ["light", "dark"]
5. Security and Privacy Considerations
This section is non-normative.
5.1. Storage of preference overrides
The overrides set by this API are intended to be persisted by the browser. These settings are clearable by any means the browser sees fit to implement.
Should this be in a normative section somewhere? See #23
5.2. Avoiding fingerprinting
This API exposes no new fingerprinting surfaces beyond that which already exist in the platform.
5.3. Permissions & User Activation
As the requestOverride
method is a promise it gives user agents more control over the process of overriding a preference.
The requestOverride
method is gated behind a UA defined algorithm for determining if the action can proceed.
This could include a user prompt, or it could be a simple check to see if the user has interacted with the page.
5.4. Sub-resources
Note: See #8 for discussion regarding this.
For the spec we can probably find an existing definition to reference, but for the purposes of this explainer:
-
Any same origin subresource (e.g. iframes) should get the overridden value.
-
Any cross-origin subresource that already has communication with the parent (e.g.
postMessage
) should get the override value. -
Any cross-origin subresource with no external communication (e.g. an SVG loaded as an image) should get the override value.
-
Any cross-origin subresource that has no communication with parent but can communicate externally should NOT get the override value.
Wherever the override value is passed down it should probably be done so in an opaque manner.
How do any potential iframe restrictions interact with permissions policy, should we restrict the ability to grant this permission to cross-origin iframes, or would these restrictions be separate from permissions policy?
colorScheme
to dark
then the iframe should see prefers-color-scheme
as dark but shouldn’t read navigator.preferences.colorScheme.override
as dark
. 6. Acknowledgements
This section is non-normative.