Skip to content

Latest commit

Β 

History

985 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Purpose

The Science Design System (SDS) brings consistency and universal standards to CZI’s science products by offering a library of high quality, reusable components that deliver predictable, accessible and easy to learn experiences. Our goal is to democratize access to tools and technologies for scientists.

This root README is the source of truth for SDS docs. The packages/components and packages/data-viz READMEs are short npm-facing summaries that link back here.

Design System Documentation

@czi-sds/components implements the Science Design System, which is documented in Storybook. Every component has a Documentation page covering how it differs from the MUI component it wraps, its props, and a runnable example of each variation. The design foundations (colors, spacing, typography, and the rest) live under Design Documentation, and it's worth getting familiar with the theme variables they describe so you can leverage the theme properly in your application.

The documentation is authored in this repository, so it ships and versions with the code.

Installation

NPM Package

Currently SDS uses Material UI v9

NOTE: Since most of the czi-sds components are built on top of Material UI's equivalent, it's also super useful to use their API documentation to learn about what you can do with the components. Many czi-sds components are style wrappers that pass props through to the MUI component without modifying them.

Migrating to SDS 24.0.0 (Material UI v9)

SDS 24.0.0 is a breaking release that moves the Material UI peer dependency from v5 to v9. If you are upgrading an existing app from an older @czi-sds/components version, follow the step-by-step guide in migration-docs/migrate-to-24.0.0.md. If a newer version of SDS is published, install that one instead. The same MUI v9 migration steps apply.

That guide covers dependency updates, MUI import and prop API changes (slots / slotProps), SDS-specific call-site updates, icon renames, and a verification checklist.

@czi-sds/components installs without direct dependencies to prevent version errors. Please ensure the following peer dependencies are also installed:

  "@emotion/css"
  "@emotion/react"
  "@emotion/styled"
  "@mui/icons-material"
  "@mui/material"
  "react"
  "react-dom"

To install @czi-sds/components and the dependencies:

// with npm
npm i @czi-sds/components @emotion/css @emotion/react @emotion/styled @mui/material @mui/icons-material react react-dom

// with yarn
yarn add @czi-sds/components @emotion/css @emotion/react @emotion/styled @mui/material @mui/icons-material react react-dom

Icons

SDS uses Phosphor Icons. Install Phosphor for the icon set, and @czi-sds/icons for the icons SDS draws itself. They are kept there either because Phosphor has no equivalent, or because Phosphor has something close and SDS wants its own version.

npm i @phosphor-icons/react @czi-sds/icons
import { HeartIcon } from "@phosphor-icons/react";
import { AtlasIcon } from "@czi-sds/icons";

<HeartIcon size={24} />
<AtlasIcon size={24} />

Both take the same props, so the only difference between them is where you import from. The Icon component in @czi-sds/components is deprecated.

React 18 (or below) note: Material UI (a peer dependency) ships react-is@19. If your app uses React 18 or below, pin react-is to match your React version to avoid runtime errors in prop-type checks. For example, with React 18 add the following to your package.json (use resolutions for Yarn, overrides for npm/pnpm):

{
  "resolutions": {
    "react-is": "^18.3.1"
  }
}

Yarn scripts

Common yarn scrips have been moved to the monorepo root. The -- syntax can be used to pass parameters to the underlying yarn scripts. For instance, to update the snapshots, use lerna run test -- -u instead of running all tests on both packages with yarn test.

  • yarn start: Starts storybook on the local machine

  • yarn build-storybook: Builds the storybook in the docs-build folder

  • yarn test-storybook: Tests current running instance of storybook

  • yarn storybook:axe: Builds the storybook and runs accessibility tests

  • yarn storybook:axeOnly: Runs accessibility tests on the latest build of the storybook inside the docs-build folder

  • yarn test: Runs jest tests

  • yarn namespace-check: Runs typescript type checking on namespace files to ensure that there are no duplicated exports

  • yarn lint: Runs linter

  • yarn build: Build the packages

  • yarn ci: Executes yarn install --frozen-lockfile in both packages

  • yarn evaluate:code <file>: Evaluates a single component file for SDS compliance

  • yarn evaluate:batch <directory>: Evaluates all .tsx/.ts files in a directory

  • To execute any script in the inner package, one can simply use the command lerna run script --scope=<package>. For instance, to run the linter only on the sci-components package, use the command lerna run lint --scope=@czi-sds/components.

Usage

@czi-sds/components comes with five main exports that help you build your app:

  1. Components - Accessible and reusable components
import React from "react";
import { Button } from "@czi-sds/components";
<Button onClick={actions.onClick} sdsStyle="rounded" sdsType="primary">
  {text}
</Button>;
  1. Mixins - Grouped styles defined by the design system
import { styled } from '@emotion/styled';
import { Typography } from "@mui/material";
import { fontHeaderXL } from "@czi-sds/components";

export const Title - styled(Typography)`
  ${fontHeaderXl}

  // which compiles to:
  font-size: 22px;
  font-weight: 600;
  letter-spacing: 0.3px;
  line-height: 30px;
`;
  1. Selectors - Helper functions that return theme variables baased on passed props
import { css, SerializedStyles } from "@emotion/react";
import styled from "@emotion/styled";
import { getColors, getCorners } from "@czi-sds/components";

export const Tag = styled("div")`
  // This is a callback function that returns more CSS rules, but the only way
  // to access the custom theme object
  ${(props) => {
    // getColors() is a selector that picks out colors from the theme object
    const colors = getColors(props);
    // getSpaces() is a selector that picks out spaces from the theme object
    const spaces = getSpaces(props);

    return `
          background-color: ${colors?.gray[500]};
          padding-bottom: ${spaces?.m}px;
          margin-bottom: ${spaces?.xxl}px;
        `;
  }}
`;
  1. CSS & SCSS Variables - Variables for the defaultTheme to use if your app doesn't support @emotion/styled
// with SCSS variables
@import "~@czi-sds/components/dist/variables";

.button-primary {
  background-color: $sds-color-primary-400;
  padding: $sds-spaces-xxs;
}

// with CSS variables
.button-primary {
  background-color: var(--sds-color-primary-400);
  padding: var(--sds-spaces-xxs);
}
  1. Tailwind - Tailwind compliant configuration for the defaultTheme to use if your app uses Tailwind

First you need to import the SDS config into your application's Tailwind config:

// tailwind.config.js

const sds = require("@czi-sds/components/dist/tailwind.json");

module.exports = {
  mode: "jit",
  content: ["./src/**/*.{tsx,scss}"],
  theme: {
    extend: sds,
  },
};

If you have existing styles that you'd like to maintain, you can pick and choose different parts of the SDS config:

// tailwind.config.js

const sds = require("@czi-sds/components/dist/tailwind.json");

module.exports = {
  mode: "jit",
  content: ["./src/**/*.{tsx,scss}"],
  theme: {
    extend: {
      ...sds,

      width: {
        ...sds.width,
        "app-modal-width": "500px",
      },

      height: {
        ...sds.width,
        "app-modal-height": "200px",
      },
    },
  },
};

After that, you should be able to use SDS Tailwind classes in your app:

export function Hello() {
  return (
    <p className="m-sds-xl px-sds-xs py-sds-s text-sds-error-400">
      Hello, World!
    </p>
  );
}

Theme System

SDS provides comprehensive light/dark theme support. To use the theme system in your React application, complete the following:

  1. Add the following HTML to your index.html at the <head> section:
// installs the sds font from google fonts
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
  href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
  rel="stylesheet"
/>
<link
  href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap"
  rel="stylesheet"
/>
  1. Import and use SDS themes in Material UI's <ThemeProvider />:

Using the default light theme:

import { ThemeProvider as EmotionThemeProvider } from "@emotion/react";
import { StyledEngineProvider, ThemeProvider } from "@mui/material/styles";
import { defaultTheme } from "@czi-sds/components";

<StyledEngineProvider injectFirst>
  <ThemeProvider theme={defaultTheme}>
    <EmotionThemeProvider theme={defaultTheme}>
      <YourApp />
    </EmotionThemeProvider>
  </ThemeProvider>
</StyledEngineProvider>;

Using programmatic theme switching:

import { ThemeProvider as EmotionThemeProvider } from "@emotion/react";
import { StyledEngineProvider, ThemeProvider } from "@mui/material/styles";
import { SDSChooseTheme } from "@czi-sds/components";

function App() {
  const [isDarkMode, setIsDarkMode] = useState(false);
  const currentTheme = SDSChooseTheme(isDarkMode ? "dark" : "light");

  return (
    <StyledEngineProvider injectFirst>
      <ThemeProvider theme={currentTheme}>
        <EmotionThemeProvider theme={currentTheme}>
          <YourApp />
        </EmotionThemeProvider>
      </ThemeProvider>
    </StyledEngineProvider>
  );
}

Creating custom themes:

If you want to create a custom theme with your own color palette, use the makeSdsSemanticAppTheme function:

import { ThemeProvider as EmotionThemeProvider } from "@emotion/react";
import { makeSdsSemanticAppTheme, makeThemeOptions } from "@czi-sds/components";
import { StyledEngineProvider, ThemeProvider } from "@mui/material/styles";
import createTheme from "@mui/material/styles/createTheme";

// Define your custom color palette following SDS color structure
const myCustomColors = {
  blue: {
    /* your blue color scale */
  },
  gray: {
    /* your gray color scale */
  },
  // ... other colors
};

// Create a custom SDS theme
const customSdsTheme = makeSdsSemanticAppTheme(myCustomColors, false); // false = light mode

// Generate Material UI theme
const appTheme = makeThemeOptions(customSdsTheme);
const theme = createTheme(appTheme);

<StyledEngineProvider injectFirst>
  <ThemeProvider theme={theme}>
    <EmotionThemeProvider theme={theme}>
      <YourApp />
    </EmotionThemeProvider>
  </ThemeProvider>
</StyledEngineProvider>;

Legacy theme override (deprecated):

⚠️ Note: defaultAppTheme is deprecated. Use SDSLightAppTheme or create custom themes with makeSdsSemanticAppTheme instead.

// DEPRECATED - Use makeSdsSemanticAppTheme instead
import { defaultAppTheme, makeThemeOptions } from "@czi-sds/components";
const customTheme = {
  /* custom properties */
};
const appTheme = makeThemeOptions({ ...defaultAppTheme, ...customTheme });
const theme = createTheme(appTheme);

πŸ’‘ CZGE example available here.

πŸ’‘ Material UI docs for custom theming available here.

Q&A

  1. Why wrapping a component with styled() doesn't style the root element as expected?

    This is likely because the component is NOT forwarding the css class name that styled() generates to the intended root element. So we likely need to update the czif component to make it work

    For example, if a czif component Foo has the following implementation, styled(Foo) won't style the wrapper <div /> as expected:

    function Foo() {
      return (
        <div>
          <ChildA />
          <ChildB />
        </div>
      );
    }

    The fix is:

    function Foo({ className }) {
      return (
        <div className={className}>
          <ChildA />
          <ChildB />
        </div>
      );
    }
  2. To style a sub-component of a @czi-sds/components component, typically we export the sub-component for the call site to import and style via styled, and then you will be able to pass back the styled sub-component to the @czi-sds/components component through prop

    For example, ComplexFilter exports ComplexFilterInputDropdown sub-component, so if you want to style it, you can do the following:

    import {
      ComplexFilter,
      ComplexFilterInputDropdown,
    } from "@czi-sds/components";
    import styled from "@emotion/styled";
    
    const StyledComplexFilterInputDropdown = styled(ComplexFilterInputDropdown)`
      color: pink;
    `;
    
    function Foo() {
      return (
        <ComplexFilter
          InputDropdownComponent={StyledComplexFilterInputDropdown}
        />
      );
    }

Code Evaluation

We provide a comprehensive evaluation script to assess LLM-generated UI components for SDS compliance and best practices.

Quick Evaluation

# Evaluate a single component
yarn evaluate:code ./my-component.tsx

# Evaluate all components in a directory
yarn evaluate:batch ./generated-components/

What It Evaluates

  • βœ… TypeScript compilation - Ensures code compiles without errors
  • βœ… ESLint compliance - Checks code quality and style
  • βœ… SDS component usage - Verifies proper use of design system components
  • βœ… Import statements - Ensures SDS components are properly imported
  • βœ… Design tokens - Checks for consistent design token usage
  • βœ… Accessibility - Verifies accessibility attributes and patterns

For detailed usage instructions and examples, see scripts/README.md.

Project status

This project is under active development. Contributions and ideas are welcome! If you would like to contribute, check out the contribution guidelines or open an issue. This project is governed under the Contributor Covenant code of conduct.

Reporting Security Issues

Please note: If you believe you have found a security issue, please responsibly disclose by contacting us at security@chanzuckerberg.com. More information is in our Security Readme

Code of Conduct

This project adheres to the Contributor Covenant code of conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to opensource@chanzuckerberg.com.

About

2021 Science Design System Component Library

Topics

Resources

Code of conduct

Security policy

Stars

35 stars

Watchers

10 watching

Forks

Releases

Packages

Used by

Contributors

Languages