Web Preferences API

Unofficial Proposal Draft,

This version:
https://specs.lukewarlow.dev/web-preferences-api/
Issue Tracking:
GitHub
Inline In Spec
Editor:
(unaffiliated)
Tests:
web-platform-tests web-preferences-api/ (not started)

Abstract

The Web Preference API aims to provide a way for sites to override the value for a given user preference (e.g. color-scheme preference) in a way that fully integrates with existing Web APIs.

Status of this document

This specification was published by the Web Platform Incubator Community Group. It is not a W3C Standard nor is it on the W3C Standards Track. Please note that under the W3C Community Contributor License Agreement (CLA) there is a limited opt-out and other conditions apply. Learn more about W3C Community and Business Groups.

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:

Alternatively, sites can and do offer site-level settings, but this currently comes with a number of issues:

Unsure how to link to html spec for the 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]
partial interface Navigator {
  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]
interface PreferenceManager {
  attribute ColorSchemePref? colorScheme;
  attribute ContrastPref? contrast;
  attribute ReducedMotionPref? reducedMotion;
  attribute ReducedTransparencyPref? reducedTransparency;
  attribute ReducedDataPref? reducedData;

  sequence<PreferenceSupportData> getSupported();
};

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. getSupported method

The getSupported() method, when invoked, must run these steps:
  1. Let supportedPreferences be a new empty sequence.

  2. For each preference that the browser supports, add a new PreferenceSupportData object to supportedPreferences with the following properties:

    • name set to the name of the preference

    • values set to a sequence of strings representing the valid values for the preference

  3. Return supportedPreferences.

3.1.1. PreferenceSupportData interface

[Exposed=Window]
interface PreferenceSupportData {
  readonly attribute DOMString name;
  readonly attribute FrozenArray<DOMString> values;
};

3.2. Preference attributes

3.2.1. Setting a preference attribute

The preference attributes, when set, must run these steps:
  1. Let preference be the preference attribute’s name.

  2. Let validValues be the preference attribute’s valid values.

  3. If value is not in validValues, return.

  4. If value is the same as the preference override for preference, return.

  5. Set the preference override for preference to value.

This algorithm needs more detail on where the overrides are stored. Also need to define what happens when a preference is overridden, with specific regard to sub-resources.

3.2.2. Getting a preference attribute

The preference attributes, when accessed, must run these steps:
  1. Let preference be the preference attribute’s name.

  2. If no overrides have been set for the preference, return null.

  3. Let result be the preference override for preference.

  4. Return result.

This algorithm needs more detail on where the overrides are stored.

3.2.3. colorScheme preference

The colorScheme preference represents 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.

enum ColorSchemePref { "light", "dark" };

3.2.4. contrast preference

The contrast preference represents 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.

Unlike the media feature this preference is not able to be set to custom this is tightly coupled to the forced-colors media feature.

enum ContrastPref { "no-preference", "more", "less" };

3.2.5. reducedMotion preference

The reducedMotion preference represents 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.

enum ReducedMotionPref { "no-preference", "reduce" };

3.2.6. reducedTransparency preference

The reducedTransparency preference represents 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.

enum ReducedTransparencyPref { "no-preference", "reduce" };

3.2.7. reducedData preference

The reducedData preference represents 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.

enum ReducedDataPref { "no-preference", "reduce" };

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. Setting a preference override

To set a preference override, the property can be set to a valid value for the preference. If an invalid value is set then this will be a no-op.

navigator.preferences.colorScheme = 'dark';

4.2. Clearing a preference override

To clear an override and return the preference to the browser default, the property can be set to null.

navigator.preferences.colorScheme = null;

4.3. Getting a preference override

To get the value of a preference override, the property can be read. Each property will return the string value indicating the preference, or null if no override is set.

const colorScheme = navigator.preferences.colorScheme; // "light" | "dark" | null

4.4. The navigator.preferences.getSupported method

This method allows a site to get the preferences supported by the browser. 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 preferenceSupportData = navigator.preferences.getSupported();
console.log(preferenceSupportData); // [ { name: 'contrast', values: ['more', 'less', 'no-preference'] }, ... ]

5. Security and Privacy Considerations

The API is currently exposed even to insecure contexts. This is probably fine but should be justified in this section probably?

This section is non-normative.

5.1. Avoiding fingerprinting

This API exposes no new fingerprinting surfaces beyond that which already exist in the platform.

5.2. Permissions & User Activation

This API does not require any permissions or user activation. It exposes no new capabilities to a site beyond that which already exists in the platform.

A site can already store a value in local storage and read into the DOM to override a preference. This API simply makes the ergonomics of this better.

5.3. 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:

Wherever the override value is passed down it should be done so in an opaque manner.

If the parent frame sets colorScheme to dark then the iframe should see prefers-color-scheme as dark but shouldn’t read navigator.preferences.colorScheme as dark.

6. Acknowledgements

This section is non-normative.

TODO fill in acknowledgements section

Conformance

Document conventions

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[CSS-COLOR-ADJUST-1]
Elika Etemad; et al. CSS Color Adjustment Module Level 1. URL: https://drafts.csswg.org/css-color-adjust-1/
[CSSOM-VIEW-1]
Simon Pieters. CSSOM View Module. URL: https://drafts.csswg.org/cssom-view/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[MEDIAQUERIES-5]
Dean Jackson; et al. Media Queries Level 5. URL: https://drafts.csswg.org/mediaqueries-5/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/

Informative References

[USER-PREFERENCE-MEDIA-FEATURES-HEADERS]
User Preference Media Features Client Hints Headers. Draft Community Group Report. URL: https://wicg.github.io/user-preference-media-features-headers/

IDL Index

[Exposed=Window]
partial interface Navigator {
  readonly attribute PreferenceManager preferences;
};

[Exposed=Window]
interface PreferenceManager {
  attribute ColorSchemePref? colorScheme;
  attribute ContrastPref? contrast;
  attribute ReducedMotionPref? reducedMotion;
  attribute ReducedTransparencyPref? reducedTransparency;
  attribute ReducedDataPref? reducedData;

  sequence<PreferenceSupportData> getSupported();
};

[Exposed=Window]
interface PreferenceSupportData {
  readonly attribute DOMString name;
  readonly attribute FrozenArray<DOMString> values;
};

enum ColorSchemePref { "light", "dark" };

enum ContrastPref { "no-preference", "more", "less" };

enum ReducedMotionPref { "no-preference", "reduce" };

enum ReducedTransparencyPref { "no-preference", "reduce" };

enum ReducedDataPref { "no-preference", "reduce" };

Issues Index

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.
Unsure how to link to html spec for the example.
This algorithm needs more detail on where the overrides are stored. Also need to define what happens when a preference is overridden, with specific regard to sub-resources.
This algorithm needs more detail on where the overrides are stored.
The API is currently exposed even to insecure contexts. This is probably fine but should be justified in this section probably?
TODO fill in acknowledgements section