@equinor/fusion-react-styles

中文文档
2.1.11发布于 2026/10/29ISCTypeScriptCommonJS构建来源已验证近 30 天下载 5856

style lib inspired by @material-ui/styles

原始使用文档
文档目录33 节
  1. Features
  2. Installation
  3. Peer Dependencies
  4. Quick Start
  5. Core Concepts
  6. 1. Creating Styles
  7. 2. Using Styles in Components
  8. 3. Dynamic Styles with Props
  9. 4. Theme-Based Styles
  10. API Reference
  11. makeStyles(stylesOrCreator, options?)
  12. createStyles(styles?)
  13. ThemeProvider
  14. useTheme<T>()
  15. createTheme(customTheme?, baseTheme?)
  16. StylesProvider
  17. createGenerateClassName(seed?)
  18. clsx
  19. Advanced Usage
  20. Scoped Styles for Module Isolation
  21. Nested Selectors
  22. Type-Safe Props with Theme
  23. Extended Themes
  24. TypeScript Support
  25. Automatic Type Inference
  26. Theme Types
  27. Type-Safe Class Access
  28. Migration from Material-UI v4
  29. React 19 Compatibility
  30. Performance Tips
  31. Contributing
  32. License
  33. Related Packages

@equinor/fusion-react-styles

npm version

A React styling library inspired by Material-UI's makeStyles API, built with JSS and designed for React 19 compatibility. This package provides a flexible, type-safe styling solution with support for theme-based styling, dynamic props, and scoped style isolation.

Features

  • ✅ React 19 Compatible - Built from the ground up for React 19
  • ✅ Type-Safe - Full TypeScript support with intelligent type inference
  • ✅ Theme Integration - Seamless integration with Fusion design system
  • ✅ Scoped Styles - Prevent CSS class name collisions with StylesProvider seeds
  • ✅ Dynamic Styles - Support for prop-based and theme-based styling
  • ✅ Performance - Cached stylesheets and optimized JSS instance
  • ✅ Nested Selectors - Full support for pseudo-selectors and nested rules

Installation

npm install @equinor/fusion-react-styles
# or
pnpm add @equinor/fusion-react-styles
# or
yarn add @equinor/fusion-react-styles

Peer Dependencies

  • React ^18 or ^19

Quick Start

import { makeStyles, ThemeProvider, theme } from '@equinor/fusion-react-styles';

const useStyles = makeStyles({
  root: {
    color: 'blue',
    padding: '16px',
  },
  title: {
    fontSize: '24px',
    fontWeight: 'bold',
  },
}, { name: 'MyComponent' });

function MyComponent() {
  const classes = useStyles();
  
  return (
    <div className={classes.root}>
      <h1 className={classes.title}>Hello World</h1>
    </div>
  );
}

function App() {
  return (
    <ThemeProvider theme={theme}>
      <MyComponent />
    </ThemeProvider>
  );
}

Core Concepts

1. Creating Styles

Use makeStyles to create a styles hook that generates CSS class names. Always provide a name option for better performance and debugging:

import { makeStyles } from '@equinor/fusion-react-styles';

const useStyles = makeStyles({
  root: {
    color: 'red',
    padding: '16px',
  },
  button: {
    backgroundColor: 'blue',
    '&:hover': {
      backgroundColor: 'darkblue',
    },
  },
}, { name: 'MyComponent' });

2. Using Styles in Components

Call the hook inside your component to get class names:

function Component() {
  const classes = useStyles();
  
  return (
    <div className={classes.root}>
      <button className={classes.button}>Click me</button>
    </div>
  );
}

3. Dynamic Styles with Props

Styles can be functions that receive props. Pass props when calling the hook:

interface ComponentProps {
  color: string;
  size: 'small' | 'large';
}

const useStyles = makeStyles({
  root: (props: ComponentProps) => ({
    color: props.color,
    padding: props.size === 'large' ? '24px' : '12px',
  }),
}, { name: 'DynamicComponent' });

function Component(props: ComponentProps) {
  const classes = useStyles(props);
  return <div className={classes.root}>Dynamic styling</div>;
}

4. Theme-Based Styles

Access theme values using theme functions. Theme properties are StyleProperty instances that require using the getVariable() method to extract CSS values:

import { makeStyles, createStyles, theme } from '@equinor/fusion-react-styles';

const useStyles = makeStyles((themeValue) =>
  createStyles({
    root: {
      color: themeValue.colors.text.static_icons__default.getVariable('color'),
      padding: themeValue.spacing.comfortable.medium.getVariable('padding'),
      backgroundColor: themeValue.colors.ui.background__default.getVariable('color'),
    },
    button: {
      backgroundColor: themeValue.colors.ui.background__default.getVariable('color'),
      '&:hover': {
        backgroundColor: themeValue.colors.ui.background__hover.getVariable('color'),
      },
    },
  }),
  { name: 'ThemedComponent' }
);

Important: Theme properties (colors, spacing, etc.) are StyleProperty instances:

  • Colors: Use theme.colors.*.getVariable('color') to get the color value as a CSS variable string
  • Spacing: Use theme.spacing.*.getVariable('padding') to get the spacing value as a CSS variable string
  • Typography: Use theme.typography.*.style.* to access typography properties (e.g., theme.typography.heading.h4.style.fontSize)

Example:

const useStyles = makeStyles((themeValue) =>
  createStyles({
    container: {
      // Color property - use getVariable('color')
      backgroundColor: themeValue.colors.ui.background__default.getVariable('color'),
      color: themeValue.colors.text.static_icons__default.getVariable('color'),
      
      // Spacing property - use getVariable('padding')
      padding: themeValue.spacing.comfortable.medium.getVariable('padding'),
      marginTop: themeValue.spacing.comfortable.small.getVariable('padding'),
      
      // Typography - access style properties directly
      fontSize: themeValue.typography.paragraph.body_short.style.fontSize,
      fontWeight: themeValue.typography.heading.h4.style.fontWeight,
    },
  }),
  { name: 'Container' }
);

API Reference

makeStyles(stylesOrCreator, options?)

Creates a hook that generates CSS class names from style definitions.

Parameters:

  • stylesOrCreator: Style rules object or a function (theme) => StyleRules
  • options.name: Required name prefix for debugging and performance. Without it, all instances share the same cache key, causing performance issues.

Returns: A hook function that returns Record<ClassKey, string> where ClassKey is inferred from your style rules, providing type-safe access to class names.

Examples:

// Static styles
const useStyles = makeStyles({
  root: { color: 'red' },
}, { name: 'MyComponent' });

// Theme-based styles
const useStyles = makeStyles((theme) => ({
  root: { 
    color: theme.colors.text.static_icons__default.getVariable('color'),
  },
}), { name: 'ThemedComponent' });

// Dynamic styles with props
const useStyles = makeStyles({
  root: (props: { color: string }) => ({
    color: props.color,
  }),
}, { name: 'DynamicComponent' });

createStyles(styles?)

Type-safe helper for creating style rules. Improves TypeScript inference for class keys, enabling type-safe access to class names.

import { createStyles, makeStyles } from '@equinor/fusion-react-styles';

const useStyles = makeStyles((theme) =>
  createStyles({
    root: { 
      color: theme.colors.text.static_icons__default.getVariable('color'),
    },
    button: { 
      padding: theme.spacing.comfortable.medium.getVariable('padding'),
    },
  }),
  { name: 'Component' }
);

function Component() {
  const classes = useStyles();
  // TypeScript will error if you try to access classes.foo - it knows the exact keys!
  return <div className={classes.root}>...</div>;
}

Benefits:

  • Type-safe class key access - TypeScript knows exactly which class keys exist
  • Better autocompletion in IDEs
  • Catches typos at compile time

ThemeProvider

Provides theme context to child components. Supports nested themes and theme composition.

Props:

  • theme: Theme object or function (outerTheme) => theme
  • children: React nodes

Example:

import { ThemeProvider, theme } from '@equinor/fusion-react-styles';

function App() {
  return (
    <ThemeProvider theme={theme}>
      <YourApp />
    </ThemeProvider>
  );
}

// Nested theme composition
function App() {
  return (
    <ThemeProvider theme={baseTheme}>
      <ThemeProvider theme={(outer) => ({ ...outer, custom: true })}>
        <YourApp />
      </ThemeProvider>
    </ThemeProvider>
  );
}

useTheme<T>()

Hook to access the current theme from ThemeProvider context.

import { useTheme } from '@equinor/fusion-react-styles';

function Component() {
  const theme = useTheme<FusionTheme>();
  
  if (!theme) {
    return <div>No theme available</div>;
  }
  
  return (
    <div style={{ 
      color: theme.colors.text.static_icons__default.getVariable('color'),
    }}>
      Hello
    </div>
  );
}

createTheme(customTheme?, baseTheme?)

Creates a new theme by merging custom properties with a base theme. Supports deep merging for nested properties like colors, typography, etc.

import { createTheme, theme } from '@equinor/fusion-react-styles';
import type { FusionTheme } from '@equinor/fusion-react-styles';

interface ExtendedTheme extends FusionTheme {
  app: {
    borderRadius: string;
    sidebarWidth: string;
  };
}

const extendedTheme = createTheme<ExtendedTheme>({
  app: {
    borderRadius: '12px',
    sidebarWidth: '300px',
  },
}, theme);

// Use in ThemeProvider
<ThemeProvider theme={extendedTheme}>
  <App />
</ThemeProvider>

StylesProvider

Creates an isolated styling scope to prevent CSS class name collisions. Critical for micro-frontends and dynamically loaded modules.

Props:

  • seed: String prefix for class names (e.g., "my-module")
  • generateClassName: Optional custom class name generator
  • jss: Optional custom JSS instance
  • children: React nodes

Example:

import { StylesProvider } from '@equinor/fusion-react-styles';

// Main app
<StylesProvider seed="main-app">
  <App />
</StylesProvider>

// Dynamically loaded module
<StylesProvider seed="dynamic-module">
  <DynamicModule />
</StylesProvider>

createGenerateClassName(seed?)

Creates a class name generator function with an optional seed prefix for isolation.

import { createGenerateClassName, StylesProvider } from '@equinor/fusion-react-styles';

const customGenerator = createGenerateClassName('my-app');

function App() {
  return (
    <StylesProvider generateClassName={customGenerator}>
      <YourApp />
    </StylesProvider>
  );
}

clsx

Utility for combining class names. Re-exported from the clsx package.

import { clsx } from '@equinor/fusion-react-styles';

const className = clsx(classes.root, isActive && classes.active, 'custom-class');

Advanced Usage

Scoped Styles for Module Isolation

When building micro-frontends or dynamically loaded modules, use StylesProvider with unique seeds to prevent CSS collisions:

import { StylesProvider, makeStyles, ThemeProvider, theme } from '@equinor/fusion-react-styles';

// Shared styles
const sharedStyles = {
  root: { color: 'blue' },
};

// Module A
const useStylesA = makeStyles(sharedStyles, { name: 'ModuleA' });

function ModuleA() {
  const classes = useStylesA();
  return <div className={classes.root}>Module A</div>;
}

// Module B
const useStylesB = makeStyles(sharedStyles, { name: 'ModuleB' });

function ModuleB() {
  const classes = useStylesB();
  return <div className={classes.root}>Module B</div>;
}

function App() {
  return (
    <ThemeProvider theme={theme}>
      {/* Each module gets its own scope */}
      <StylesProvider seed="module-a">
        <ModuleA />
      </StylesProvider>
      
      <StylesProvider seed="module-b">
        <ModuleB />
      </StylesProvider>
    </ThemeProvider>
  );
}

Even though both modules use the same styles object, they'll generate different class names:

  • Module A: module-a-makeStyles-root-1
  • Module B: module-b-makeStyles-root-1

Nested Selectors

Full support for CSS-in-JS nested selectors:

import { clsx } from '@equinor/fusion-react-styles';

const useStyles = makeStyles({
  root: {
    color: 'blue',
    '&:hover': {
      color: 'red',
    },
    '& .child': {
      padding: '10px',
    },
    '&$disabled': {
      opacity: 0.5,
    },
  },
  disabled: {},
}, { name: 'NestedComponent' });

function Component() {
  const classes = useStyles();
  const [disabled, setDisabled] = useState(false);
  
  return (
    <div className={clsx(classes.root, disabled && classes.disabled)}>
      <div className="child">Child element</div>
    </div>
  );
}

Type-Safe Props with Theme

Use TypeScript to ensure type safety with dynamic styles and theme:

import { makeStyles, createStyles, theme } from '@equinor/fusion-react-styles';

interface StyleProps {
  color: string;
}

const useStyles = makeStyles((themeValue) =>
  createStyles({
    root: (props: StyleProps) => ({
      ...themeValue.typography.paragraph.body_short.style,
      color: props.color,
      padding: themeValue.spacing.comfortable.medium.getVariable('padding'),
      backgroundColor: themeValue.colors.ui.background__default.getVariable('color'),
    }),
  }),
  { name: 'MyComponent' }
);

function Component(props: StyleProps) {
  const classes = useStyles(props);
  return <div className={classes.root}>Styled component</div>;
}

Extended Themes

Extend the Fusion theme with custom properties:

import { createTheme, theme, makeStyles } from '@equinor/fusion-react-styles';
import type { FusionTheme, StyleDefinition } from '@equinor/fusion-react-styles';

interface AppTheme extends StyleDefinition {
  app: {
    borderRadius: string;
    sidebarWidth: string;
  };
}

const extendedTheme = createTheme<AppTheme>({
  app: {
    borderRadius: '12px',
    sidebarWidth: '300px',
  },
});

// Use extended theme with makeStyles
const useStyles = makeStyles((themeValue: typeof extendedTheme) =>
  createStyles({
    root: {
      borderRadius: themeValue.app.borderRadius,
      padding: themeValue.spacing.comfortable.medium.getVariable('padding'),
    },
  }),
  { name: 'ExtendedThemeComponent' }
);

TypeScript Support

This package is written in TypeScript and provides full type definitions. All APIs are fully typed with intelligent inference:

Automatic Type Inference

Type inference works automatically, and using createStyles provides even better type safety:

// Basic type inference - works, but ClassKey is inferred as string
const useStyles = makeStyles({
  root: { color: 'red' },
  button: { padding: '10px' },
}, { name: 'Component' });
const classes = useStyles(); // classes: Record<string, string>

// With createStyles - ClassKey is inferred as literal union type
const useStyles = makeStyles((theme) =>
  createStyles({
    root: { 
      color: theme.colors.text.static_icons__default.getVariable('color'),
    },
    button: { 
      padding: theme.spacing.comfortable.medium.getVariable('padding'),
    },
  }),
  { name: 'Component' }
);
const classes = useStyles(); // classes: Record<'root' | 'button', string>
// TypeScript will error if you try to access classes.foo - it knows the exact keys!

Theme Types

The FusionTheme type can be extended with custom properties:

import type { FusionTheme, StyleDefinition } from '@equinor/fusion-react-styles';

interface MyAppTheme extends StyleDefinition {
  customProperty: string;
}

const useStyles = makeStyles((theme: FusionTheme<MyAppTheme>) => ({
  root: {
    color: theme.colors.text.static_icons__default.getVariable('color'),
    custom: theme.customProperty, // Fully typed!
  },
}), { name: 'Component' });

Type-Safe Class Access

When using createStyles, the return type is Record<ClassKey, string> where ClassKey is a literal union of your style keys. This provides:

  • Compile-time safety: TypeScript errors when accessing undefined class keys
  • Better autocompletion: IDEs show exactly which class names are available
  • Refactoring support: Rename class keys and TypeScript will catch all usages

Migration from Material-UI v4

This package provides a similar API to @material-ui/styles v4 but is built for React 19 compatibility. The main differences:

  1. No Material-UI dependency - Uses JSS directly
  2. React 19 compatible - No compatibility issues
  3. Improved TypeScript types - Better type inference
  4. Scoped styles - Enhanced StylesProvider with seed-based isolation
  5. Required name option - Always provide a name in makeStyles options for performance

Most code should work with minimal changes:

// Before (Material-UI v4)
import { makeStyles } from '@material-ui/styles';

// After (this package)
import { makeStyles } from '@equinor/fusion-react-styles';
// Add name option to makeStyles
const useStyles = makeStyles({ ... }, { name: 'ComponentName' });

React 19 Compatibility

This package is fully compatible with React 19 and has been tested extensively. The implementation uses React 19's new APIs and avoids deprecated patterns.

Performance Tips

  1. Always provide a name option - Without it, all instances share the same cache key, causing unnecessary re-renders and performance issues.

  2. Use createStyles for better type safety - While optional, it improves TypeScript inference and provides better autocompletion.

  3. Memoize style objects when possible - If creating styles inside components, consider moving them outside or memoizing them.

  4. Leverage style caching - The package automatically caches stylesheets based on styles, theme, and name, so identical style definitions are reused.

Contributing

Contributions are welcome! Please read our Contributing Guide for details.

License

ISC

版本与发布记录

@equinor/fusion-react-styles 共发布 60 个版本,首次发布于 2021/03/18;过去 12 个月发布了 12 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
2.1.11latest2026/10/2915 天前
2.1.102026/10/2321 天前
2.1.92026/10/2024 天前
2.1.82026/07/283 个月前
2.1.72026/07/283 个月前
2.1.62026/06/244 个月前

其他发布通道:248 → 0.5.3-248.0,table → 0.1.0-table.0,preview → 2.0.0-preview.5。

关于 @equinor/fusion-react-styles 的常见问题

@equinor/fusion-react-styles 是什么?

style lib inspired by @material-ui/styles

如何安装 @equinor/fusion-react-styles?

在项目目录运行 npm install @equinor/fusion-react-styles,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(^18 || ^19)、styled-components(^6)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@equinor/fusion-react-styles 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@equinor/fusion-react-styles 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@equinor/fusion-react-styles 可以商用吗?

@equinor/fusion-react-styles 使用 ISC 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@equinor/fusion-react-styles 的下载量有多少?

根据 npm 官方下载统计,@equinor/fusion-react-styles 在 2026/10/14 – 2026/11/12 这 30 天内被下载 5,856 次,日均约 195 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@equinor/fusion-react-styles 还在维护吗?

最新版本 2.1.11 发布于 2026/10/29(15 天前);至今共发布 60 个版本,其中过去 12 个月发布了 12 个;首次发布于 2021/03/18。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。