Development workflow

Installation & configuration

Asset types

There are 3 main types of code assets that the Design System will give you as a developer:

  1. Normalize - A reset and base css stylesheet that is required in any app that uses the Design System components.
  2. Core - A collection of basic values for color, type, layout, etc.
  3. Components - UI Widgets

Installation

Install Normalize

npm install @pluralsight/ps-design-system-normalize

For CSS configuration options, follow the "CSS configuration" section instructions.

Install Core

npm install @pluralsight/ps-design-system-core

If you use Core values via CSS custom properties, installing Core is not required because those properites are included in :root in Normalize. If, however, you want to import into JS and use the JS variables, you'll want to install Core separately.

For CSS configuration options, follow the "CSS configuration" section instructions.

For usage options, follow the "Core usage" section instructions.

Install components

All components are built on React as a UI framework. Install it as a peer dependency along with the appropriate renderer.

npm install react react-dom

All components support theming and have a peer dependency on the Theme package. Install with:

npm install @pluralsight/ps-design-system-theme

Each component is installed separately. For example:

npm install @pluralsight/ps-design-system-button

The JavaScript is compiled as ES5 and dual-published as CommonJS and ES Modules.

Polyfills

Pluralsight still supports IE11 and compiling to ES5 doesn't solve the issue of using JS APIs that don't exist in that browser. You will likely want to bundle a global polyfill with your application such as core-js.

It will be challenging to not bloat your polyfill because what exact polyfills are needed by the Design System has not been documented well to date. For now, either including the full core-js or testing in IE11 is recommended.

CSS configuration

Webpack bundling

You'll need to include the CSS for Design System Core and components.

npm install style-loader css-loader

Add a loader chain for CSS to your webpack.config.js. Make sure it processes CSS from the installed Design System packages by including those paths. For example:

module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [{ loader: 'style-loader' }, { loader: 'css-loader' }],
include: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'node_modules', '@pluralsight'),
],
},
],
},
}

With CSS Modules

module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
{ loader: 'style-loader' }
{
loader: 'css-loader',
options: {
modules: {
mode: (resourcePath) => {
if (resourcePath.includes('@pluralsight/ps-design-system')) {
return "global";
}
return "local";
},
localIdentName: '[local]__[hash:base64:5]',
},
},
}
],
include: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'node_modules', '@pluralsight'),
],
},
],
},
}

PostCSS

If you're using Core as CSS variables, you'll want to process your app css with PostCSS in order to give fallback values to CSS custom properties. Processing Design System component CSS with PostCSS is not needed because the CSS in components has already been processed and should be browser-ready.

Install the tool dependencies:

npm install postcss-import postcss-preset-env

And add a postcss.config.js:

module.exports = {
plugins: {
'postcss-import': {},
'postcss-preset-env': { browsers: ['Last 2 versions', 'IE >= 11'] }
}
}

For webpack bundling, install the extra loader:

npm install postcss-loader cssnano

And add postcss-loader to then end of your loader chain:

use: ['style-loader', 'css-loader', 'postcss-loader'],

Sass

Core publishes Sass variables. Components with vanilla CSS publish a .scss stylesheet (that's identical to the .css) but it's not what's used internal to components. You could access it from node_modules if desired for your use case.

To use Sass, installed the required build tools, such as:

npm install node-sass

If you use Webpack for loading CSS, you'll also need to install your additional CSS loaders:

npm install sass-loader

And add the loader to the chain that processes CSS:

use: ['style-loader', 'css-loader', 'sass-loader']

Next.js

The latest version of Next.js should handle CSS natively. No additional configuration is required. Versions 10 and 11 of Next.js have a restriction on import CSS from node_modules. This has had a lot of community pushback and there's a current RFC to change it.

In the meantime, you'll need to work around the restriction by using this library:

npm install next-global-css

And editing your next.config.js:

const { withGlobalCss } = require('next-global-css')
const withConfig = withGlobalCss()
module.exports = withConfig({
/* Next.js config options here */
})

Configuration examples

See the examples on Github for config in project context.

Core usage

After, installation, use Core in the flavor of your choice. JavaScript or CSS are equally recommended.

Import JavaScript

import * as core from '@pluralsight/ps-design-system-core'
<button style={{ backgroundColor: core.colorsPink[6] }}>Click</button>

Import CSS

To use the Core variables in CSS:

.mySelector {
color: var(--ps-colors-pink-6);
}

Importing the Core package is not required because Normalize should already be on every page.

Import SASS

To use the Core variables in SASS:

@import '~@pluralsight/ps-design-system-core/dist/index.module.scss';
.mySelector {
color: $ps-colors-pink6;
}

Overriding component styles

Use the standard

The Design System is meant, among other things, to provide continuity of the user experience across Pluralsight products. But sometimes it will make sense to override a visual standard. This should not be the common case. And it should be done by product designers and developers who are clear about the tradeoffs and have a clear rationale of the value that such an override would create. If the value add isn't significant, the standard should be kept.

Limit the effects of overrides

Design System component CSS is not modularized. This is so that targetting and overriding become simple. But it does come with tradeoffs. In a way, it's going back to the olden days. Now the CSS for Design System components all lives in the global namespace of a web page. Thus we all need to be careful to be a good citizens and not unintentionally clobber the styles of other things. Limit the effects of your override. To do this, be as specific as possible.

Never override tag names

Do not target tag names like a, h1, etc. The effect of such changes are much too broad. Leave this to the normalize stylesheet.

Use a custom selector

All components should allow a className prop to be passed so you can use your own CSS selectors. This is also true for exposed sub-components in compound component packages.

Use the className prop to pass your own selector. Never target the CSS selectors of a component directly.

/* good */
<Button className="my-custom-button" />
/* bad */
// my-stylesheet.css
.psds-button {
color: var(--that-old-orange-i-like);
}

Use child selectors where needed

In some cases, you might want to override the styles of a child element. That element is not exposed as an exported subcomponent. The only way to target it is through the CSS selector it ships with. In this case, that's is ok, provided the child element is targeted as a child selector of a selector specific to your application.

/* good */
.my-custom-avatar .psds-avatar__initials {
display: none;
}
/* bad */
.psds-avatar__initials {
display: none;
}

Using child combinators to target direct children or traversing nodes in selectors to get to child nodes is generally discouraged. This ties you to the implementation of the internal structure, and changes to this structure are not considered changes to the public API, are not versioned as such and could thus could break at any time.