Installation

If you're planning to use Reshaped with any of the listed frameworks – check their setup documentation or visit community repository with starter projects.

Install the latest version from NPM. You can track our latest releases in our changelog.

npm install reshaped

Create a postcss.config.js file in your project root and importing a PostCSS config from Reshaped. Our config enables custom media queries provided by Reshaped, autoprefixer and cssnano for build optimizations. This config can be extended with your own plugins.

const { config } = require("reshaped/config/postcss");
module.exports = config;

If you're generating a theme that modifies the default viewport breakpoints – you'll have to pass the path to the generated media.css file to the postcss config. We provide an alternative getConfig function to handle this behavior.

const path = require("path");
const { getConfig } = require("reshaped/config/postcss");

module.exports = getConfig({
  themeMediaCSSPath: path.resolve(__dirname, "src/themes/my-theme/media.css"),
});

Reshaped relies on CSS Modules and PostCSS to keep our styles isolated and support missing browser features. Additionally, we're keeping CSS imports in our JS files to ensure CSS tree-shaking is working as expected. This way, you will get CSS only for components you're using in the product instead of importing CSS for the whole library.

Import some of the components along with the Reshaped provider and try them out:

import { Button, Container, Reshaped } from "reshaped";
import "reshaped/themes/reshaped/theme.css";

const App = () => {
  return (
    <Reshaped theme="reshaped">
      <Container width="652px">
        <Button href="/">Get started</Button>
      </Container>
    </Reshaped>
  );
};

We're aiming for the best modern solution - so Reshaped is shipped as ESM build. So only the components that you're using in your code will stay in your product bundle. It also means that we keep ES imports and exports in our code, and you have to compile it further with Babel in your project.

To avoid style differences between server and browser rendering:

  • add the default dir value for RTL/LTR to the <html> element
  • add data-rs-theme and data-rs-color-mode attributes for picking the default theme on the <html> element
// RTL with light mode
<html dir="rtl" data-rs-theme="reshaped" data-rs-color-mode="light">

// LTR with dark mode
<body data-rs-theme="reshaped" data-rs-color-mode="dark">

Reshaped doesn't automatically update the color mode of your product based on the selected user preference in their operating system since it's not always the expected behavior. Instead you might pick one of the following approaches:

  • In case your application is client-only, you can use media queries matching inside React.useLayoutEffect which will be triggered before the first application DOM rendering. Note that this logic shouldn't be called on the same level as Reshaped provider but deeper inside your application. Otherwise, this code won't have access to the Reshaped context.
import { useTheme } from "reshaped";

const Component = () => {
  const { setColorMode } = useTheme();

  React.useLayoutEffect(() => {
    const mq = window.matchMedia?.("(prefers-color-scheme: dark)");
    if (!mq.matches) return;

    setColorMode(mq.matches ? "dark" : "light");
  }, [setColorMode]);
};
  • If you're working with SSR, your code won't have access to the media query API on the server, which means you won't be able to set the color mode at that point. This issue will be solved in browsers with user-preference-media-features-hint. Meanwhile an option that you can use, is relying on an inline script that will have access to the browser APIs and will be excecuted before html is rendered. Here is an example, we use on this website that works with local storage and automatically applies the system color mode if it wasn't selected before.
<script
  dangerouslySetInnerHTML={{
    __html: `
      const matcher = window.matchMedia("(prefers-color-scheme: dark)");
      const systemColorMode = matcher.matches ? "dark" : "light";
      const storedColorMode = localStorage.getItem("__reshaped-mode");

      document.documentElement.setAttribute("data-rs-color-mode", storedColorMode || systemColorMode);
      matcher.addEventListener("change", () => {
        document.body.setAttribute("data-rs-color-mode", systemColorMode);
      });
  `,
  }}
/>

We're using Inter as the main font in our default theme to keep the experience cross-platform for designers and developer. However, we don't fetch it automatically since there are multiple ways of doing that depending on the framework you use.

It's publicly available so you can install it from various resources. In case you don't want to install it, Reshaped will fallback to system fonts or you can change the font tokens in your product theme definition in both React and Figma.

Reshaped can be used with any iconset, only using a few icons built into the components. For all our examples and documentation, we're using Feather icons.

We recommend using a react-feather npm package to avoid copying the svg source code manually to your project:

npm install react-feather
import { Home } from "react-feather";
import { Icon, Button } from "reshaped";

const Component = () => {
  return (
    <>
      <Icon svg={Home} />
      <Button icon={Home}>Homepage</Button>
    </>
  );
};

For the cases when you can't use our ESM build, we also provide a pre-built Webpack JS and CSS bundles. In order to use them, import Reshaped components from reshaped/bundle and import the CSS from reshaped/bundle.css once in your root application file.

import { Button, Container, Reshaped } from "reshaped/bundle";
import "reshaped/bundle.css";
import "reshaped/themes/reshaped/theme.css";

const App = () => {
  return (
    <Reshaped theme="reshaped">
      <Container width="652px">
        <Button href="/">Get started</Button>
      </Container>
    </Reshaped>
  );
};

When using with TypeScript, make sure to change moduleResolution to nodenext or node16 to make type definitions for the bundle work correctly.