Using the web-features package to build Baseline-aware tooling
Baseline tooling relies on accurate, current data about web platform feature support. While the Web Platform Status Dashboard offers a queryable HTTP API, fetching that data on demand isn't practical for every tool. For local, reliable lookups, the web-features npm package provides a structured dataset you can integrate directly into linters, IDE extensions, and other developer tools.
Package exports and feature data structure
Install the package as a project dependency, then import the named exports you need:
npm install web-features
import { features, groups, browsers, snapshots } from 'web-features';
Each export serves a different purpose:
features: An array of feature objects, each representing one web platform feature. This is the primary export for most tooling.browsers: Descriptions of the browsers included in the data.groups: Logical groupings of features, useful for narrowing to areas like CSS or JavaScript.snapshots: ECMAScript version mappings for corresponding JavaScript features (e.g., ES2022, ES2023).
Feature objects expose these properties for Baseline logic:
id: The unique key identifying the feature. Note this is the object key itself, not a property inside the object. For example, CSS Grid has the ID"grid".compat_features: An array of granular BCD keys that the feature aggregates.name: The human-readable feature name, such as"Container Queries".description: A short summary of the feature.group: Identifies the feature's group, matching entries in thegroupsexport.baseline: Baseline status, one offalse(Limited availability),"low"(Newly available), or"high"(Widely available).baseline_high_date: Date the feature became Widely available; omitted if not applicable.baseline_low_date: Date the feature became Newly available; omitted for Limited availability features.
Here is the complete data object for CSS subgrid:
"subgrid": {
"caniuse": "css-subgrid",
"compat_features": [
"css.properties.grid-template-columns.subgrid",
"css.properties.grid-template-rows.subgrid"
],
"description": "The subgrid value for the grid-template-columns and grid-template-rows properties allows a grid item to inherit the grid definition of its parent grid container.",
"description_html": "The <code>subgrid</code> value for the <code>grid-template-columns</code> and <code>grid-template-rows</code> properties allows a grid item to inherit the grid definition of its parent grid container.",
"group": "grid",
"name": "Subgrid",
"spec": "https://drafts.csswg.org/css-grid-2/#subgrids",
"status": {
"baseline": "low",
"baseline_low_date": "2023-09-15",
"support": {
"chrome": "117",
"chrome_android": "117",
"edge": "117",
"firefox": "71",
"firefox_android": "79",
"safari": "16",
"safari_ios": "16"
}
}
}
Common lookup patterns
Look up the Baseline status for a specific feature
The most direct approach: specify a feature ID to read its Baseline data from status.baseline.
import { features } from 'web-features';
function getBaselineStatus (featureId) {
return features[featureId]?.status.baseline;
}
This reveals whether a feature is Limited, Newly, or Widely available, and includes threshold dates where applicable.
Look up the Baseline status for a specific BCD key
BCD (browser-compat-data) keys describe granular features, such as a single CSS property value or behavioral subfeature. The overall feature-level Baseline aggregates all constituent BCD keys, which can hide inconsistencies — some keys may have stronger browser support than others. For CSS linters checking specific property-value pairs, this granularity matters.
Starting with web-features 3.6.0, inspect status.by_compat_key to find a key's Baseline status:
import { features } from 'web-features';
function getBaselineStatus (featureId, bcdKey) {
return features[featureId]?.status.by_compat_key[bcdKey];
}
For instance, getBaselineStatus('outline', 'css.properties.outline') returns:
{
"baseline": "low",
"baseline_low_date": "2023-03-27",
"support": {
"chrome": "94",
"chrome_android": "94",
"edge": "94",
"firefox": "88",
"firefox_android": "88",
"safari": "16.4",
"safari_ios": "16.4"
}
}
Sort features by Baseline status
You can iterate over all features and bucket them by status. This pattern is useful for displaying feature lists filtered or grouped by their Baseline state.
import { features } from "web-features";
const webFeatures = Object.values(features);
const widelyAvailable = webFeatures.filter(feature => {
return feature.status.baseline === 'high';
});
const newlyAvailable = webFeatures.filter(feature => {
return feature.status.baseline === 'low';
});
const limitedAvailability = webFeatures.filter(feature => {
return feature.status.baseline === false;
});
Filter features by group
Using the groups export alongside features lets you narrow searches, for example to every feature belonging to View Transitions:
import { features, groups } from 'web-features';
const groupKeys = Object.keys(groups);
const featuresData = Object.values(features);
const viewTransitionsGroup = groupKeys.find(groupKey => {
return groupKey === 'view-transitions';
});
const viewTransitionsFeatures = featuresData.filter(feature => {
return feature.group === viewTransitionsGroup;
});
Building a Baseline-aware CSS linter
A practical use case combines these lookups in a CSS linter. CSS linters evaluate at-rules, pseudo-elements, properties, and values. To report accurate Baseline warnings, you need the status of each token by its BCD key rather than by the parent feature.
Using a parser like CSSTree, a stylesheet becomes an AST. Consider this CSS rule:
.foo {
word-break: auto-phrase;
}
Its AST structure looks like:
{
"type": "StyleSheet",
"children": [
{
"type": "Rule",
"prelude": {
"type": "SelectorList",
"children": [
{
"type": "Selector",
"children": [
{
"type": "ClassSelector",
"name": "foo"
}
]
}
]
},
"block": {
"type": "Block",
"children": [
{
"type": "Declaration",
"important": false,
"property": "word-break",
"value": {
"type": "Value",
"children": [
{
"type": "Identifier",
"name": "auto-phrase"
}
]
}
}
]
}
}
]
}
While walking the AST, map property names to BCD keys under css.properties. For the property word-break, that key is css.properties.word-break. Then locate the associated feature and check its status:
// Assuming we only know the BCD key and not the feature ID.
const bcdKey = 'css.properties.word-break';
const [featureId, feature] = Object.entries(features).find(([id, feature]) =>
feature.compat_features?.includes(bcdKey)
) || [];
const status = feature?.status.by_compat_key[bcdKey];
The result for the word-break property:
{
"baseline": "high",
"baseline_high_date": "2018-03-30",
"baseline_low_date": "2015-09-30",
"support": {
"chrome": "44",
"chrome_android": "44",
"edge": "12",
"firefox": "15",
"firefox_android": "15",
"safari": "9",
"safari_ios": "9"
}
}
A status of "high" means the property is widely available — no linter warning needed. Next, assess the value. The AST shows auto-phrase as the value. Append it to the property key: css.properties.word-break.auto-phrase. For this property-value pair, web-features reports a non-Baseline status:
{
"baseline": false,
"support": {
"chrome": "119",
"chrome_android": "119",
"edge": "119"
}
}
That non-Baseline result triggers a warning, informing the developer that this value won't work predictably across major browser engines.
Existing tools built on web-features
Several production tools already consume this data:
- The
eslint-cssproject appliesweb-featuresin itsuse-baselinerule to flag specifications that aren't yet Baseline. - Visual Studio Code hovercards pull from the package to surface Baseline information for CSS and HTML features.
- MDN's
yarirenderer uses the data in Baseline indicator banners on feature pages, such as for theabs()CSS function.



