Skip to content

About

A React implementation of Echoes, Sonar's design system.

Resources

Stars

9 stars

Watchers

15 watching

Forks

Latest commit

 

History

763 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

echoes-react

Build Status Releasability status Quality Gate Status

A React implementation of Echoes, Sonar's Design System.

Installation

Requirements

This library can be installed with npm or Yarn.

Install the library

npm install @sonarsource/echoes-react
# or
yarn add @sonarsource/echoes-react

Install peer dependencies

Echoes React has several peer dependencies that must be installed in your project:

npm install @emotion/react @emotion/styled react-intl
# or
yarn add @emotion/react @emotion/styled react-intl

These dependencies are required for:

  • @emotion/react & @emotion/styled: CSS-in-JS styling
  • react-intl: Internationalization support

Usage

Providers

Make sure to setup the following Providers at the root of your app:

Echoes Provider

The EchoesProvider is required to provide theming and configuration context for all Echoes components.

Intl Provider

The IntlProvider from react-intl is necessary for translations. See this page for more information. The i18n keys file contains the list of keys that should be translated and provided by your IntlProvider. Make sure to have the IntlProvider wrapping the EchoesProvider.

CSS variables

Import the Sonar brand CSS once (@sonarsource/echoes-react/styles/sonar.css), typically in the module that renders the providers.

To use custom brand values, create your own CSS file instead of importing the default one. Use sonar.css as a template: it must define the same CSS custom properties under the same selectors (:root for base tokens, [data-echoes-theme='light'] and [data-echoes-theme='dark'] for themed tokens), otherwise theme switching will not work.

Fonts

The brands' CSS may use specific fonts (e.g. Sonar uses Inter and Ubuntu-Mono). If you want them to apply, they need to be provided by the client project. If you can, use the CDN:

@import 'https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap';
@import 'https://fonts.googleapis.com/css2?family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400;1,700';

Otherwise, you'll have to define the fonts (like the CDN does) and serve the .woff files yourself (e.g. as static assets):

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100;
  font-display: swap;
  src: url('../fonts/Inter/Inter-Thin.woff2') format('woff2');
}
... for each variant

Otherwise, the fonts will fall back to defaults provided by the browser & OS.

Router adapter

Echoes does not depend on any router. Links, buttons with a to, breadcrumbs, dropdown menu links and navigation components use the router adapter you pass to the required router prop of EchoesProvider.

An adapter is an object with two members:

  • Link: a component that renders an anchor and performs client-side navigation. It receives to, state, reloadDocument, ref and the regular anchor attributes.
  • usePathname: a hook returning the current pathname, without basename, search or hash. Echoes uses it to highlight the active navigation items.

Define the adapter once at module scope so its reference stays stable. If the adapter relies on router hooks, EchoesProvider must be rendered inside your router.

With react-router-dom:

import { Link, useLocation } from 'react-router-dom';
import type { EchoesRouter } from '@sonarsource/echoes-react';

export const reactRouterAdapter: EchoesRouter = {
  Link,
  usePathname: () => useLocation().pathname,
};

With Next.js (app router):

import NextLink from 'next/link';
import { usePathname } from 'next/navigation';
import { toHref } from '@sonarsource/echoes-react';
import type { EchoesRouter, EchoesRouterLinkProps } from '@sonarsource/echoes-react';

function Link({ reloadDocument, state, to, ...props }: EchoesRouterLinkProps) {
  // `toHref` serializes `to` and normalizes the `?` / `#` prefixes of `search` and `hash`.
  const href = toHref(to);

  return reloadDocument ? <a href={href} {...props} /> : <NextLink href={href} {...props} />;
}

export const nextRouterAdapter: EchoesRouter = { Link, usePathname };

Pass router={null} if your app has no client-side router: links render plain anchors, every navigation is a full page load, and the active route is read from window.location.

Active navigation items are detected automatically only for absolute destinations (/path or { pathname: '/path' }). For relative or search-only destinations, pass isActive explicitly.

Stacking Context

In order to have tooltips and other overlay components appear above the rest of the UI, it is probably necessary to have a Stacking Context for your app. This means the root app component should define a new one, or be wrapped in a component that does it.

The easiest way to start a new Stacking Context is to provide your app root with the following CSS properties:

isolation: isolate;
position: relative;

Complete Setup Example

import { BrowserRouter } from 'react-router-dom';
import { IntlProvider } from 'react-intl';
import { EchoesProvider } from '@sonarsource/echoes-react';
import '@sonarsource/echoes-react/styles/sonar.css'; // Import the sonar brand or include your own!
import { reactRouterAdapter } from './reactRouterAdapter';

function App() {
  return (
    <IntlProvider locale="en" messages={messages}>
      <BrowserRouter>
        <EchoesProvider router={reactRouterAdapter}>
          <div className="app-root" style={{ isolation: 'isolate', position: 'relative' }}>
            <YourAppRoot />
          </div>
        </EchoesProvider>
      </BrowserRouter>
    </IntlProvider>
  );
}

Use components

import { Checkbox } from '@sonarsource/echoes-react';

See available components and usage in storybook: https://echoes-react.netlify.app/

Testing with Echoes components in your app

Rendering components

To render app components that use Echoes components internally you need to make sure your test render function also provides the necessary context providers detailed in the Providers section above. You can also configure the EchoesProvider with tooltipsDelayDuration={0} to disable the tooltip delay during tests, which can help avoid flaky tests due to tooltips not appearing on time.

Jest

The lib only provides an ES module bundle. If you use Jest for your tests (or a similar library) make sure your transform preprocessor goes through @sonarsource/echoes-react to make it runnable on Node.js. You can do that by adding an exception in your transformIgnorePatterns, for example:

transformIgnorePatterns: [`/node_modules/(?!@sonarsource/echoes-react)`],

Contributing

VSCode Configuration

We recommend VSCode to work on this project. There is a .vscode folder containing:

  • A list of recommended extensions
    • Install them through the marketplace
  • A template for necessary (and recommended) settings: settings.template.json
    • Copy it and save it as settings.json
    • You must open the project directly. Adding its folder in an existing workspace might not work, as the typescript configuration must be defined at workspace level.

Run storybook

Use the following command to run both the build watcher and the storybook server in dev mode:

yarn dev

Tests

To run tests, use the following command:

yarn jest

Build

To build the lib, use the following command:

yarn build

Generated files

The lib is built on top of some generated files like the design-tokens or the icons fonts. These generated files are versioned in the src/generated and i18n folders.

Generated Icons font

We generated an optimized version of the material-symbold-rounded font that we use for our icons. The whole font contains thousands of icons and weighs more than 4Mb, so we generate a subset of it containing only the icons we use in the design system, reducing its size to a few Kb.

If you add new icons you must run the following command to generate the new optimized font:

yarn build-fonts

Generated Design Tokens

Our raw design tokens files that are created on Figma are stored inside the design-tokens/tokens folder. We can't use these tokens as is, so we transform them using style-dictionary to css variable format and store them in the src/generated folder. We also generate a few other files to help us with typings.

There can be multiple brands representing the first layer of tokens. All brands are built automatically.

If new design tokens are added to the raw Figma file, we must run the following command to generate the new design tokens css variables for all brands:

yarn build-tokens

Generated i18n keys file

We use the react-intl library for internationalization. We store our translations in the i18n/keys.json file. This file is generated based on all the translation keys contained in our components. This file is mainly useful for the products that use the lib to know what keys they should translate.

If you add new translation keys, you must run the following command to generate the new i18n/keys.json file:

yarn build-intl-keys

Releasing

Release process

Troubleshooting

Common Issues

"Cannot resolve module" errors with Vite/Webpack

Make sure all peer dependencies are installed, see the Installation section above.

Missing component styles or functionality

Ensure you have wrapped your app with all required providers in the correct order and configured a proper stacking context, see Providers section above.

Tooltips not appearing above other UI elements

If tooltips or other overlay components don't appear correctly, ensure you have configured a stacking context, see Providers section above.

Router context errors

If your router adapter relies on router hooks (like useLocation from react-router-dom), EchoesProvider and every Echoes link must be rendered inside your router. In tests, wrap them in a test router (e.g. MemoryRouter), or pass router={null} to EchoesProviderForTests to get plain anchors.

License

Copyright 2023-2025 SonarSource. Licensed under the GNU Lesser General Public License, Version 3.0

About

A React implementation of Echoes, Sonar's design system.

Resources

Stars

9 stars

Watchers

15 watching

Forks

Releases

Packages

Used by

Contributors

Languages