Skip to content

Tooling

Edit on GitHub

A collection of developer tools that improve the experience of working with @volvo-cars/css: editor support, linting, and runtime utilities.


The official Volvo Car CSS IntelliSense extension for Visual Studio Code provides autocomplete, hover previews, and quick access to documentation for design system classes and tokens.

Intelligent suggestions for class names, CSS custom properties, and custom media tokens as you type.

Autocomplete demo showing class name suggestions in VS Code

See the complete CSS for any Volvo Car class name or token by hovering over it.

Hover preview demo showing CSS output for a class name in VS Code

To include @volvo-cars/edls-css classes in IntelliSense, add the following to your .vscode/settings.json:

{
"volvoCarsCss.metaFiles": [
"./node_modules/@volvo-cars/css/dist/meta.json",
"./node_modules/@volvo-cars/edls-css/dist/meta.json"
]
}

We provide both Stylelint and ESLint configurations to catch issues early and enforce design system best practices.

We recommend using Stylelint with the Volvo Car configuration to lint your CSS.

Terminal window
yarn add --dev stylelint @volvo-cars/stylelint-config

In your .stylelintrc:

extends:
- '@volvo-cars/stylelint-config'
# Optional: enforce a consistent CSS property order
- '@volvo-cars/stylelint-config/order'

This configuration will warn you about common issues such as using physical properties (margin-left) instead of logical properties (margin-inline-start).

The @volvo-cars/eslint-plugin-css plugin enforces best practices when using Volvo Car CSS classes in your markup.

Terminal window
yarn add --dev eslint @volvo-cars/eslint-plugin-css
RuleDescription
deprecated-classDetect deprecated class names
conflicting-classDetect conflicting class names on the same element
redundant-classDetect redundant (duplicate-effect) class names
no-custom-classDetect class names that don’t belong to the system
plugins:
- '@volvo-cars/css'
rules:
'@volvo-cars/css/deprecated-class': 'error'
'@volvo-cars/css/redundant-class': 'warn'
'@volvo-cars/css/conflicting-class': 'warn'
'@volvo-cars/css/no-custom-class':
[
'warn',
{
whitelist: ['custom-class-to-whitelist'],
whitelistPattern: '^somePrefix-.*',
},
]

To use @volvo-cars/edls-css together with the ESLint plugin, add the following to your .eslintrc so the plugin recognises EDLS classes:

settings:
css:
metaFiles:
- '@volvo-cars/css/meta.json'
- '@volvo-cars/edls-css/meta.json'

@volvo-cars/css ships two helper functions for working with class name strings: cssJoin and cssMerge. They replace the need for third-party libraries like clsx or classnames.

Conditionally joins strings of class names together, filtering out falsy values.

import { cssJoin } from '@volvo-cars/css/utils';
cssJoin('bg-secondary text-primary', hasContent && 'px-24');
cssJoin(['bg-secondary text-primary'], hasContent && 'px-24');

Results in the string bg-secondary text-primary px-24.

Joins classes like cssJoin, but also merges conflicting class names that apply to the same CSS property. This lets you override styles without worrying about source order in the stylesheet.

Consider a card component that accepts a className prop:

function Card(props) {
return (
<div
{...props}
className={`bg-secondary px-16 py-32 ${props.className || ''}`}
/>
);
}
function SuccessCard(props) {
return <Card {...props} className="bg-feedback-green p-64" />;
}

<SuccessCard> renders class="bg-secondary px-16 py-32 bg-feedback-green p-64". Which background color and padding win? That depends on the order they appear in the .css files — not the order in the className string.

import { cssMerge } from '@volvo-cars/css/utils';
function Card(props) {
return (
<div
{...props}
className={cssMerge('bg-secondary px-16 py-32', props.className)}
/>
);
}
function SuccessCard(props) {
return <Card {...props} className="bg-feedback-green p-64" />;
}

Now <SuccessCard> renders class="p-64 bg-feedback-green" — the later arguments win, and conflicting properties are resolved predictably.

If you don’t want consumers to override a specific style, place it last:

cssMerge('px-16 py-32', props.className, 'bg-secondary');

Since bg-secondary is added last, it will always win regardless of what props.className contains.