import { Meta, Source } from '@storybook/addon-docs/blocks';

<Meta title="Concepts/Developer/Styling Components" />

## Styling components

To style Fluent UI components `makeStyles` is used.

`makeStyles` is a homegrown CSS-in-JS implementation (inspired by stylex) which generates atomic CSS classes. Get started by simply importing

```js
import { makeStyles } from '@fluentui/react-components';
```

To style a component, you need to call `makeStyles` in a module scope to create a React hook to be used inside a component.

The `makeStyles` call accepts an object of items where each key is a unique identifier and each value is an object with styles. The call returns an object with classes mapped to these unique identifiers.

<!-- TODO: format as <Code /> -->

```jsx
import { makeStyles } from '@fluentui/react-components';

const useStyles = makeStyles({
  root: { color: 'red' },
});

function Component() {
  const classes = useStyles();

  return <div className={classes.root} />;
}
```

### Merging component styles

There are cases where you need to merge classes from multiple `useStyles` calls.

#### ⚠It is not possible to simply concatenate `useStyles` classes

To properly merge the classes, you need to use `mergeClasses()` function, which performs merge and deduplication of atomic classes generated by `makeStyles()`.

When `mergeClasses()` is called, it merges all classes from first to last - the latter argument overwrites the previous ones (similar to `Object.assign()`).

```jsx
const useStyles = makeStyles({
  blueBold: {
    color: 'blue',
    fontWeight: 'bold',
  },
  red: {
    color: 'red',
  },
});

function Component() {
  const classes = useStyles();

  const first = mergeClasses(classes.blueBold, classes.red); // { color: 'red', fontWeight: 'bold' }
  const second = mergeClasses(classes.red, classes.blueBold); // { color: 'blue', fontWeight: 'bold' }
}
```

### Mapping props and state to styles

Both `makeStyles` and `mergeClasses` are simple. . They are unaware of component state and props. Developers should merge and apply appropriate parts of the `useStyles` call based on their requirements.

```jsx
const useStyles = makeStyles({
  root: { color: 'red' },
  rootPrimary: { color: 'blue' },
});

function Component(props) {
  const classes = useStyles();

  return <div className={mergeClasses('ui-component', classes.root, props.primary && classes.rootPrimary)} />;
}
```

### Applying classes passed from parent

The same approach is used to apply classes passed from parent component. Again, you need to use `mergeClasses()` to properly merge and deduplicate the classes. Note again, that the order of application is important in `mergeClasses()` so that parent classes overwrite component classes.

```jsx
function Component(props) {
  const classes = useStyles();

  return <div className={mergeClasses(classes.root, props.className /* these definitions have higher precedence */)} />;
}
```

### Applying theme to styles

No matter what theme is used, the component styles are always the same. The only way how to change the component styling is through theme tokens which can be used in style values.

```js
const useStyles = makeStyles({
  root: { display: 'flex' },
  rootPrimary: theme => ({ color: theme.alias.color.neutral.neutralForeground3 }),
});
```

Those tokens are resolved to CSS variable usages. `ThemeProvider` component is responsible for setting the CSS variables in DOM and changing them when theme changes. When theme is switched, only the variables are changed, all styles remain the same.

### Incorrect usages

This section shows and describes anti-patterns which should never be used.

```js
const useStyles = makeStyles({
  root: { color: 'red' }, // Do not use colors directly as those are not theme-able. Always use colors from a theme
});

function Component(props) {
  const classes = useStyles();

  const wrongClasses = classes.root + ' ' + props.className; // Never concatenate class strings, always use mergeClasses()
  const wrongClasses2 = mergeClasses(props.className, classes.root); // Incorrect order of classes - as the latest wins, props.className should be last to override the component styles
}
```

## Overriding FUI component styles

To override an appearance of a FUI component, you use the exactly same approach - You call makeStyles/useStyles in your code and pass the resulting classes through `props`.

```jsx
const useOverrides = makeStyles({
  button: theme => ({ color: theme.alias.color.neutral.neutralForeground3 }),
  buttonIcon: { border: '1px solid red'},
  link: { fontWeight: 'bold },
});

function MyComponent() {
  const overrides = useOverrides();

  return (
    <>
      <Button className={overrides.button} icon={{className: overrides.buttonIcon, children: <CallIcon />}} />
      <Link className={overrides.link} />
    </>
  );
}
```
