/rivet-icons

A minimal set of icons for the Rivet design system

Primary LanguageJavaScriptBSD 3-Clause "New" or "Revised" LicenseBSD-3-Clause

Rivet Icons

Icons for the Rivet Design System.

View Demo

Contents

  1. Quick start
  2. Repo structure
  3. Install
  4. Getting started
  5. Usage
  6. Use the icon element
  7. Use internal SVG symbols
  8. Use external SVG symbols
  9. Use inline SVG
  10. Change icon color
  11. Change icon size
  12. Accessibility
  13. Build a custom icon set
  14. API
  15. Request a new icon
  16. Icon specifications
  17. Run the docs site

Quick start

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Rivet icon example</title>
    <link rel="stylesheet" href="https://unpkg.com/rivet-icons@2/dist/rivet-icons.css">
    <script defer src="https://unpkg.com/rivet-icons@2/dist/rivet-icons.js"></script>
    <script type="module" src="https://unpkg.com/rivet-icons@2/dist/rivet-icon-element.js"></script>
  </head>
  <body>
    <rvt-icon name="heart"></rvt-icon>
  </body>
</html>

Repo structure

The following are some notable contents in this repo.

Path Description
./dist Production files (CSS, HTML, JS, SVG).
./src Source SVG files.

Install

Install the package to import production files or build a custom icon set.

npm install --save rivet-icons

This package can also be browsed and linked to through UNPKG.

Getting started

Rendering icons requires up to three pieces of content: CSS styles, SVG images, and optionally the Rivet Icon Element.

The easiest way to incorporate these parts is to link to them in the <head> of the page.

<link rel="stylesheet" href="path/to/rivet-icons.css">
<script defer src="path/to/rivet-icons.js"></script>
<script type="module" src="path/to/rivet-icon-element.js"></script>

rivet-icons.css loads the required styles. rivet-icons.js appends the SVG images as internal SVG symbols in the <body>. The defer attribute means that the symbols file will be requested immediately, but it won't block rendering the rest of the page. rivet-icon-element.js loads the <rvt-icon> custom element as a convenience for using these icons, although it is optional. The type="module" attribute will cause the script to load just like using the defer attribute, but it also will be ignored by older browsers, such as Internet Explorer. In such a case, <rvt-icon> would look and behave just like an empty <span> element.

If the build process allows, embed rivet-icons.html in the page in replacement of linking to rivet-icons.js. This avoids a use of JavaScript and saves a network request, at the expense of browser caching. This technique may be preferred if only a few icons are used on an independent page.

If external SVG symbols are used, then rivet-icons.svg will be used instead of rivet-icons.js or rivet-icons.html.

Usage

Once the icon files are loaded in the page, choose a way to use the icons.

  1. Use the icon element (<rvt-icon>).
  2. Use internal SVG symbols.
  3. Use external SVG symbols.
  4. Use inline SVG.
Consideration Element Internal External Inline
Works in latest browsers 1 Yes Yes Yes Yes
Works in Internet Explorer No 2 Yes Maybe 3 Yes
Requires JavaScript Yes No Maybe 3 No
Change icon color 4 Yes Yes Yes Yes
Change icon with CSS variables Yes No No No
Change icon with JavaScript Yes Yes Yes Yes
Can build custom icon set Yes Yes Yes Yes
Requires rivet-icons.css Yes Yes Yes Yes
Requires rivet-icons.js or rivet-icons.html Yes Yes No No
Requires rivet-icons.svg No No Yes No
Requires rivet-icon-element.js Yes No No No
Requires rvt-icon-*.svg or rvt-icon-*.html No No No Yes
  1. Latest browser versions of Chrome, Edge, Firefox, and Safari.
  2. Internet Explorer does not support custom elements or CSS variables.
  3. Internet Explorer does not support SVG external content. Use the svg4everybody polyfill to provide support.
  4. Icons inherit their color from the CSS color property.

Use the icon element

Render the icon in HTML.

<rvt-icon name="heart"></rvt-icon>

Use JavaScript to dynamically change the icon via the name attribute. This example uses JSX (React).

const iconName = isFavorited ? 'heart-solid' : 'heart'
const icon = (<rvt-icon name={iconName} />)

Use CSS to dynamically change the icon via the --rvt-icon variable. Set its value to the CSS variable of the desired icon ("heart" is var(--heart)). In order to not pollute the global :root scope, icon variables are declared at the level of the rvt-icon element. That means, --rvt-icon should only be used on the rvt-icon element itself, not on an ancestor.

In this example, the button toggles the value of aria-pressed for screen reader users, while the icon updates between the solid heart and outlined heart for visual users. Change the icon color with the color property.

<button aria-pressed="true" class="favorite">
  <rvt-icon class="favorite__icon"></rvt-icon>
  Favorite
</button>
/* Do this. */
.favorite[aria-pressed="false"] .favorite__icon {
  --rvt-icon: var(--heart);
}

.favorite[aria-pressed="true"] .favorite__icon {
  --rvt-icon: var(--heart-solid);
  color: red;
}

/* This won't work. */
.favorite[aria-pressed="false"] {
  --rvt-icon: var(--heart);
}

.favorite[aria-pressed="true"] {
  --rvt-icon: var(--heart-solid);
  color: red;
}

CSS variable declarations always override the name attribute. In this case, the icon will render as heart-solid, not heart.

<rvt-icon name="heart" class="heart-solid"></rvt-icon>
.heart-solid {
  --rvt-icon: var(--heart-solid);
}

A "flash of unstyled content" happens when <rvt-icon> is used before the element definition is registered. This looks like the icon is briefly invisible, as if visibility: hidden is applied and suddenly removed. To avoid this, either place the rivet-icons.html or rivet-icons.js references before any use of <rvt-icon>, or wait to render content until after it registers with whenDefined().

window.customElements.whenDefined('rvt-icon').then(() => {
  render()
})

Use internal SVG symbols

If not wanting to use <rvt-icon>, then render an icon with the following snippet. All href values reference the SVG symbol ID, in the format of #rvt-icon-[name]. With this method, the icon's color still changes with the CSS color property, but the icon itself cannot change with the --rvt-icon CSS variable.

<span class="rvt-icon">
  <svg aria-hidden="true" focusable="false">
    <use href="#rvt-icon-heart"></use>
  </svg>
</span>

Use external SVG symbols

If wanting to use rivet-icons.svg (rather than rivet-icons.js or rivet-icons.html), then add the path to the file, using a similar snippet as internal SVG symbols. Optionally include the svg4everybody polyfill to support Internet Explorer.

<span class="rvt-icon">
  <svg aria-hidden="true" focusable="false">
    <use href="path/to/rivet-icons.svg#rvt-icon-heart"></use>
  </svg>
</span>

Use inline SVG

Icons can be placed inline in HTML. Copy and paste the contents of any inline icon (rvt-icon-[name].html) in the page.

<span class="rvt-icon">
  <!-- Paste `rvt-icon-heart.html` here. -->
</span>

If the development environment allows it, prefer to import individual icons, rather than copying and pasting them. This example is how it could be done with React, with the right build configurations.

import 'rivet-icons/dist/rivet-icons.css'
import heart from 'rivet-icons/dist/rvt-icon-heart.html'

const HeartIcon = (
  <span
    className='rvt-icon'
    dangerouslySetInnerHTML={{ __html: heart }} />
)

Inline icons (rvt-icon-[name].html) are identical to the source icons (rvt-icon-[name].svg) except for changing some SVG attributes, given the context of use. xmlns is not needed in HTML documents. width and height are set with the .rvt-icon class. aria-hidden is added, as icons are decorative images.

Change icon color

The icon color is inherited through the color property. It behaves just like text color.

<rvt-icon name="heart" class="color-red"></rvt-icon>
.color-red {
  color: red;
}

Change icon size

Icons are sized at 16 square pixels, but padding and margin can be adjusted to fit into other contexts. For example, to increase the dimensions to 24 square pixels (while keeping the icon at its current scale), add 0.25rem (4px) padding to the icon. This can be done with Rivet spacing utility classes.

<!-- 16x16 -->
<rvt-icon></rvt-icon>
<span class="rvt-icon"></span>

<!-- 24x24 -->
<rvt-icon class="rvt-p-all-xxs"></rvt-icon>
<span class="rvt-icon rvt-p-all-xxs"></span>

<!-- 32x32 -->
<rvt-icon class="rvt-p-all-xs"></rvt-icon>
<span class="rvt-icon rvt-p-all-xs"></span>

Accessibility

Icons are considered decorative images. They are hidden from screen readers via <svg aria-hidden="true">. However, text alternatives should still be provided wherever icons are used.

In this example, the link text of "Favorites" is presented to all users. The icon acts as a visual anchor and perhaps a legend to the rest of the page. Providing an accessible description of the icon itself (in addition to the link text) provides little value and may be undesired.

<a href="/favorites">
  <rvt-icon name="heart"></rvt-icon>
  Favorites
</a>

Revisiting a previous example, this icon is used to visually indicate the pressed state of the button. It is "heart" if the button is not pressed. It is "heart-solid" if the button is pressed. aria-pressed communicates the necessary information to screen readers. This attribute value changes the icon via CSS in order to communicate equivalent information to visual users.

<button aria-pressed="true" class="favorite">
  <rvt-icon class="favorite__icon"></rvt-icon>
  Favorite
</button>

If a visual label is not desired (because the icon itself may be sufficient for the context), the text label should still be available to screen readers. Wrap the label with the .rvt-sr-only class.

<button aria-pressed="true" class="favorite">
  <rvt-icon class="favorite__icon"></rvt-icon>
  <span class="rvt-sr-only">Favorite</span>
</button>

Some older browsers could cause keyboard focus issues with SVG, but they are easy to work around. First, add <svg focusable="false"> so the SVG does not gain focus in Internet Explorer and early versions of Edge. Second, add whitespace around <use> so Safari 10 keeps all focusable elements tabbable. The <rvt-icon> element and the rvt-icon-*.html include these fixes.

Build a custom icon set

The Rivet icon set includes dozens of icons. If only a few icons or custom icons are needed, then build a custom icon set. After installing the rivet-icons package, write a Node script to build the icons.

// ./scripts/build-icons.js
const { buildIcons } = require('rivet-icons')

async function buildCustomIcons () {
  await buildIcons({
    icons: [
      'arrow*',
      'plus'
    ],
    include: [
      './src/assets/*',
      './favicon.svg'
    ],
    out: 'build'
  })
}

buildCustomIcons()

// Generates:
// ./build/rivet-icon-element.js
// ./build/rivet-icons.css
// ./build/rivet-icons.html
// ./build/rivet-icons.js
// ./build/rivet-icons.svg
// ./build/rvt-icon-[name].html
// ./build/rvt-icon-[name].svg

This could be integrated as a npm run script and run before (or after) another build step. The package npm-run-all is a good way to sequence multiple scripts.

{
  "scripts": {
    "build": "npm-run-all -s build-icons build-app",
    "build-app": "webpack",
    "build-icons": "node scripts/build-icons.js"
  }
}

See the rivet-icons-webpack-react guide to learn how to incorporate Rivet icons in a Webpack/React environment.

API

buildIcons()

buildIcons(options: Object) => void

Returns a promise that resolves when the icon files are written.

await buildIcons()

options.icons

Type: string[] (optional)

Default: ['*']

Specify the Rivet icons to include. By default, it includes the entire set. To include specific icons, pass an array of icon names or glob patterns. Exclude the .svg file extention. If an empty array is used, no icons will be included.

buildIcons({
  icons: ['arrow*', 'plus']
})

// Generates icon set with:
// arrow-down
// arrow-left
// arrow-right
// arrow-up
// plus

options.include

Type: string[] (optional)

Default: []

Specify an array of custom icons to include in the icon set, using glob patterns. Any custom icons matching a Rivet icon name will override the Rivet icon. Any non-SVG files are ignored.

buildIcons({
  include: ['assets/*']
})

// Generates icon set with all Rivet icons
// and all SVG files in the local assets directory.

options.out

Type: string (optional)

Default: '.'

Specify the directory for generated icon files. It defaults to the current working directory.

buildIcons({
  out: 'build'
})

// Outputs the icon set to the `build` directory.

Request a new icon

Submit a new issue to request a new icon. Include anything that may help to visually describe this new icon, such as examples from other icon sets, examples of usage in various apps or websites, the SVG source code of the icon, or even a sketch.

Icon specifications

Each icon is drawn to the following specifications:

  • 16×16px grid
  • 2px stroke for all icon outlines
  • Expand all strokes before exporting and merge/flatten artwork in to one group.
  • Set fill attribute to currentColor on exported SVGs.

Run the docs site

To run the docs site locally, clone or download this repo.

Install dependencies.

npm install

Build the site and start a local development server.

npm run start

Open the browser to localhost.

http://localhost:8080/