Overview
Wave is a tailor-made library of user interface components, behaviors and utilities for the responsive and modern day web. It provides you with a set of reusable building blocks that establish an extensible design system.
Goal of the library is to provide utilities you need to get started crafting web UI at Volue. It serves both developers and designers: enabling the former to implement consistent user interfaces much faster using a range of pre-built components, while the latter can quickly compose new prototypes by selecting existing materials—without getting lost in specifics. It's a huge win for reduced development and design effort.
Structure
Wave documentation is organized into a few useful sections.
This section includes core typographic and base element styles. Here you will also find a collection of powerful typographic, layout, spacing and color micro-helpers that can be mixed-and-matched in any number of combinations. Micro-helpers are the smallest, most flexible units in Wave—they should help in many situations and contexts.
Components are larger, more complex units: requiring multiple elements, classes and often Javascript behavior. Some features you can find here are: grid system, modals, spinners, overlays, panels and so on. Components live on their own, but together they combine system.
You can find all sorts of useful JavaScript utilities here. Need to trigger JavaScript when a responsive breakpoint is hit? Wave has you covered.
Templates
Templates consist mostly of components and helpers stitched together. They are very concrete and provide context for the smaller building blocks.
Resources
This section includes resources such as icons, color palettes and other assets available in Wave.
Getting started
Include NPM Token
Since @wave
is a private NPM scope, your project (both locally and in CI pipeline) needs to be authenticated with NPM to fetch packages.
The best way to authenticate with NPM is using an access token. You can find the authentication token with read-only permissions required to download the package in the wiki page on GitHub. If, for some reason, you're not able to access the page, please contact the Design Team.
To get more details, please read the instructions at Using private packages in a CI/CD workflow.
# Do this on your local machine and commit the `.npmrc` to git
cd path/to/your/app
echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}' >> .npmrc
# Add this environment variable both locally and on your CI/CD
# Substitute `READ_ONLY_NPM_TOKEN` with a real token:
# https://github.com/Volue/wave/wiki/NPM-authentication-token
export NPM_TOKEN=READ_ONLY_NPM_TOKEN
# Now whenever you `npm install`, NPM will know you have read-only access
# to the private packages in @volue scope.
Installation
The easiest way to get Wave is by installing it via NPM.
Stable version:
npm install @volue/wave --save
Bleeding edge version with the most recent features:
npm install @volue/wave@next --save
Files found in the dist/
folder in the NPM package are minified and unminified resources ready for production.
There are also JavaScript source files in src/
folder in case you would like to integrate Wave
with a module bundler of your choice.
Include Wave in Your App
Copy resources
Once you’ve installed @volue/wave
package into your project, you should copy the library artifacts from node_modules
to your assets directory where they can be accessed.
This is required to properly serve assets required by Wave such as styles, fonts and favicons.
npx copy-wave-assets ./public
copy-wave-assets
will create a directory named wave
in the location you’ve specified (./public
in the example above). See copy-wave-assets -h
for more information.
It is recommended to add a copy script to your package.json
that runs copy-wave-assets
. You should call this script while starting up or building your app to make sure you’ve always got the latest artifacts copied over automatically.
"scripts": {
"sync-wave-assets": "npx copy-wave-assets SPECIFY_PATH",
"build": "npm run sync-wave-assets && CMD_TO_BUILD_YOUR_APP",
"start": "npm run sync-wave-assets && CMD_TO_START_YOUR_APP"
}
CMD_TO_BUILD_YOUR_APP
could be your custom script or some popular CLI tool such as react-scripts build
or ng-build
depending on your project.
Include resources in your HTML markup
Once you have a copy task in place and have copied the library over, you can serve Wave's subresources using <link>
and <script>
tags.
- Add inline style with
@font-face
rules in the<head>
to load initial, highly optimized versions of our web fonts. Also remember to preload the initial web fonts using<link rel=”preload”>
. - Inline
wave-head.min.js
in the<head>
of your HTML template. The script will asynchronously load "full" versions of our web fonts to enable more stylistic variants and features. You can customize the path to the web fonts directory by adding<meta name="fontsDir" content="/path/to/fonts">
in the<head>
. By default fonts will be looked up in/fonts
directory. - Link to the CSS file in your HTML template to include the main Wave styles.
- Add a script tag to your HTML template to use the JavaScript (script should be included right before the closing
</body>
tag, this is to prevent render blocking and provide a faster perceived page load). Wave will be available asWave
in the window object.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="theme-color" content="#00829b">
<meta name="fontsDir" content="/wave/fonts">
<link rel="icon" href="/favicon.ico" sizes="any">
<link rel="icon" type="image/svg+xml" href="/wave/images/favicon.svg">
<link rel="icon" type="image/png" sizes="192x192" href="/wave/images/favicon-192.png">
<link rel="apple-touch-icon" href="/wave/images/favicon-180.png">
<link rel="preload" href="/wave/fonts/SourceSansPro-Regular-initial.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/wave/fonts/FKDisplay-Regular-initial.woff2" as="font" type="font/woff2" crossorigin>
<title>...</title>
<style>
@font-face {
font-family: 'Source Sans Pro';
src: url(/wave/fonts/SourceSansPro-Regular-initial.woff2) format("woff2"), url(/wave/fonts/SourceSansPro-Regular-initial.woff) format("woff");
font-display: swap;
}
@font-face {
font-family: 'FK Display';
src: url(/wave/fonts/FKDisplay-Regular-initial.woff2) format("woff2"), url(/wave/fonts/FKDisplay-Regular-initial.woff) format("woff");
font-display: swap;
}
</style>
<!-- wave-head.min.js inlined -->
<script>!function(e){"use strict";var o,f,r,a,n=function(o){for(var f,r=e.document.getElementsByTagName("meta"),a=0;a<r.length;a++)if(r[a].name&&r[a].name==o){f=r[a];break}return f}("fontsDir");o=null!=n?n.content:"/fonts","fonts"in document&&(f=new FontFace("FK Display","url("+o+"/FKDisplay-Regular.woff2) format('woff2'), url("+o+"/FKDisplay-Regular.woff) format('woff')"),r=new FontFace("Source Sans Pro","url("+o+"/SourceSansPro-Regular.woff2) format('woff2'), url("+o+"/SourceSansPro-Regular.woff) format('woff')"),n=new FontFace("Source Sans Pro","url("+o+"/SourceSansPro-Italic.woff2) format('woff2'), url("+o+"/SourceSansPro-Italic.woff) format('woff')",{style:"italic"}),a=new FontFace("Source Sans Pro","url("+o+"/SourceSansPro-SemiBold.woff2) format('woff2'), url("+o+"/SourceSansPro-SemiBold.woff) format('woff')",{weight:"600"}),Promise.all([f.load(),r.load(),n.load(),a.load()]).then(function(o){o.forEach(function(o){document.fonts.add(o)})})),!("fonts"in document)&&"querySelector"in document&&((a=document.createElement("style")).innerHTML="@font-face { font-family: 'FK Display'; src: url("+o+"/FKDisplay-Regular.woff2) format('woff2'), url("+o+"/FKDisplay-Regular.woff) format('woff'); }@font-face { font-family: 'Source Sans Pro'; src: url("+o+"/SourceSansPro-Regular.woff2) format('woff2'), url("+o+"/SourceSansPro-Regular.woff) format('woff'); }@font-face { font-family: 'Source Sans Pro'; src: url("+o+"/SourceSansPro-Italic.woff2) format('woff2'), url("+o+"/SourceSansPro-Italic.woff) format('woff'); font-style: italic; }@font-face { font-family: 'Source Sans Pro'; src: url("+o+"/SourceSansPro-SemiBold.woff2) format('woff2'), url("+o+"/SourceSansPro-SemiBold.woff) format('woff'); font-weight: 600; }",document.head.appendChild(a))}(this);</script>
<link rel="stylesheet" href="wave/wave.min.css">
</head>
<body>
<p class="alpha">Hello, world!</p>
<script src="wave/wave.min.js"></script>
<script>
(function() {
var initWave = Wave.default;
// initWave() contains some global bootstrapping logic such as
// identyfing browser capabilities and appendinng relevant classes to
// root HTML element as well as instantiating some behaviour (e.g.
// dropdowns) available via hooks in markup (`.js-triggerDropdown` etc)
initWave();
// Create new component instances
// var toasterInstance = Wave.Toaster(/* options */);
// var toggleSwitchInstance = Wave.ToggleSwitch(/* options */);
// Use utils
// Wave.utils.debounce(/* someFunc */)
})();
</script>
</body>
</html>
Usage with JS bundlers
If you're building a web application and already have a bundler in place such as Webpack, it's best to import Wave using ES6 import syntax like this:
// in your app's entry point
import initWave from '@volue/wave';
initWave();
Then when you need some functionality, you import relevant module(s):
import { Toaster, ToggleSwitch } from '@volue/wave';
import { debounce } from '@volue/wave/utils';
This way only imported modules will get included in your final bundle instead of entire library (tree shaking).
Wave is also compatible with legacy CommonJS and AMD formats in case your environment does not support ES6 import syntax. For instance, if you are using CommonJS modules in your application, you can:
// require NPM module
// note that tree shaking benefits mentioned above are absent when using this syntax
var Wave = require('@volue/wave');
var initWave = Wave.default;
initWave();
// var toasterInstance = Wave.Toaster(/* options */);
// var toggleSwitchInstance = Wave.ToggleSwitch(/* options */);
// Wave.utils.debounce(/* someFunc */)
Note on browser support
The complete experience should work in the last two versions of all evergreen browsers: Chrome, Opera, Firefox and Safari. Wave also aims to support Internet Explorer 11+. Support for other browsers is not strictly guaranteed, but accounted for whenever possible.
Compatibility matrix:
IE11 | Chrome | Firefox | Safari | Chrome (Android) | Mobile Safari |
---|---|---|---|---|---|
B | A | A | A | A | A |
A-grade browsers are fully supported. B-grade browsers will gracefully degrade the experience without impacting the function.
Contributing
Would you like to help make Wave project better? Awesome!
We use Github issues to track all bugs and potential updates and additions to the design system. To contribute you will need to sign up for a free GitHub account and be a member member of Volue GitHub organization.
If you find an issue or have an idea for a feature, please do file it in our repository issue tracker. We gladly accept pull requests that add documentation, fix bugs and, in some circumstances, add new features to Wave (be sure to read the contribution guide).