---
# System prepended metadata

title: Summary

---

# Summary

`react-theming` provides a set of tools for creating themable
components. The `createComponent` tool extends unstyled components by
applying given options and contextual overrides provided through React
context, computes injected props including `classes`, `slots`, and
`slotProps`. Styles are computed only when encountering unique theme
objects per component, resulting in optimized performance.

Example usage:

```jsx
import { SliderBase } from 'implementation';
import { createComponent } from '@fluentui/react-theming';

export const Slider = createComponent(SliderBase, {
  // the themable name of the component
  name: 'Slider'

  // the set of replacement tokens to be injected into the styles
  tokens,

  // The css styling to be injected as a `classes` prop
  styles

  // A dictionary of React components representing the actual subcomponents to be used by the Slider
  slots
});

// Created components can be further extended to alter look and feel.
export const RedSlider = createComponent(Slider, {
  tokens: { railColor: 'red' }
});
```

Theming is achieved by using the `Provider` component (also provided):

```tsx
// Create a theme with a token override for the Slider.
const theme = createTheme({
  components: {
    Slider: {
      tokens: {
        railColor: 'green',
      },
    },
  },
});

// Render the slider using the theme.
const App = () => (
  <Provider theme={theme}>
    <Slider />
  </Provider>
);
```

## Principles

Key principles of `react-theming`:

- allow any base component following the contract (explained in
  "createComponent API surface") to be extended (and therefore
  styled).
- should be future proof, and not coupled to a specific styling/css implementation

## Who is `createComponent` for?

### Component authors

Components created with `createComponent` are styleable by end user
applications, and provide a separation of concerns when adressing
multiple design systems or styling implementations.

### Application authors

Application authors should find value using `createComponent`, as
existing library components will be easily extendable, and new
components can be effortlessly created that tie in to existing themes.

## When should I use `createComponent`?

- When creating a component that should be themeable.
- When overriding major details of an existing component. (Explained
  later in "Overriding (tokens|slots) with a new component".)

## What's in a theme?

> TODO: document theme

# Using components created with `createComponent`

Components created with `createComponent` should exist in the context
of a `Provider`. All other patterns common to developing with React
controls should be standard.

## Styling components with a theme

> TODO: document theme

## Customizing with tokens

Frequently, design needs of a specific product conflict with that of
the base design system. To accomodate necessary changes, `Tokens`
exist to allow easy modification of most all aspects of look and feel.

A token is a key that corresponds to a value, usually from from the
applied theme. Examples of tokens might be `fontSize`, `fontFamily`,
`borderRadius`, `animationDuration`, and `labelHoveredBackground`.

### Setting tokens with a theme

To understand the set of tokens that a specific component understands,
refer to the documentation of that component. For this example, we will
assume that a `Button` component exists that supports the following
tokens:

- `backgroundColor`
- `fontSize`
- `backgroundHoverColor`

To override any (or all) of the Button's tokens, an object should be
provided within the theme under:

```{.json}
{
  "components": {
    "Button": {
      "tokens": {
        "values": "here..."
      }
    }
  }
}
```

Tokens are represented by the following:

1.  Function

    A functional token is the preferred method of adjusting look and
    feel. Functional tokens reference values in the applied theme.

    ```javascript
    {
      "components": {
        "Button": {
          "tokens": {
            "fontSize": t => t.fonts.base, // pull some value from the theme
          }
        }
      }
    }
    ```

2.  Literal value

    A literal value allows a token to be hard-coded. It is considered
    the least desirable (as it will never be affected by other changes
    in the theme).

    A literal token in practice looks like:

    ```{.json}
    {
      "components": {
        "Button": {
          "tokens": {
            "fontSize": 12
          }
        }
      }
    }
    ```

3.  Dependent value

    There are several cases where the value of a token is based on a
    calculation of another value. For instance, the background hover
    color of a button might be desired to be a shade lighter than the
    default background color of the button. (In order to specify this,
    assume we have a `lighten()` function available.)

    ```javascript
    {
      "components": {
        "Button": {
          "tokens": {
            "backgroundHoverColor": {
              dependsOn: ['backgroundColor'],
              value: ([backgroundColor: Color]) => invert(backgroundColor)
            }
          }
        }
      }
    }
    ```

### Customizing components with variants

`createComponent` supports variants, where a variant represents a new
prop that implies a set of styles. Examples of expected variants for a
button might be `circle`, `size`, or `primary`.

Variants are specified in the call to `createComponent` along with
additional tokens and styles. Variant arguments represent the keys in
the defintion passed to `createComponent`.

```javascript
const DeluxeButton = createComponent(Button, {
  variants: {
    size: {
      small: { // used via <DeluxeButton size="small" />
        tokens: t => {
          return { fontSize: t.fonts.smallest }
        }
      },
      large: { // used via <DeluxeButton size="large" />
        tokens: t => {
          return { fontSize: t.fonts.largest }
        }
      },
    },
    primary: {
      true: { // used via <DeluxeButton primary />
        tokens: t => {
          return { shadowColor: t.accents[1]; }
        },
        styles: tokens => {
          return {
            root: {
              boxShadow: "5px 5px #{tokens.shadowColor}"
            }
          }
        }
      }
    }
  },
});
```

## Customizing with slots

While tokens affect the look and feel of rendered elements, `slots`
provides a way to make more significant adjustments to a component\'s
structure and behavior.

A slot is a rendered DOM element or higher level control that can be
replaced at runtime.

As an example, a `Checkbox` might choose to render a `label` element to
hold descriptive text. If a use-case called for a proprietary
`<MyLabel />` control instead of a `label`, that slot could be targeted
for replacement.

### Overriding slots with a theme

To override a slot from a theme, specify a reference to the component in
the theme.

```javascript
import { MyLabel } from 'my-library';
{
  "components": {
    "Checkbox": {
      "slots": {
        "label": MyLabel
      }
    }
  }
}
```

### Overriding slots with a new component

`createComponent` can also specify slot assignments directly. (This is
the expected usage for component libraries.)

```javascript
import { MyLabel } from 'my-library';

const MyCheckbox = compse(Checkbox, {
  slots: {
    label: MyLabel
  }
});
```

# Creating a base component

A base component is an unstyled component that contains desired behaviors.

A base component should anticipate 2 special `props` and behave accordingly.

## `props.slots`

`slots` defines the control that should be rendered in each
slot. The outermost component should always be named `root`, and other
child components should be given predictable names and documented.

## `props.slotProps`

There will be an entry in `slotProps` for each accompanying `slot`.
The base component is responsible for merging user-provided props with
`slotProps`, then passing them to the according `slot` for rendering.

# Theming a component

In order to apply a theme to a component, each base component should
be wrapped by `createComponent` along with accompanying styling.

## Understanding tokens

Tokens are the exclusive means of getting data from a theme into a
component. Tokens should be specified for every aspect of a control\'s
look and feel.

Tokens should be named according to the following anatomy:

    {slot (or none for root)}{property}{state (or none for default)}

Examples:

- `thumbSizeHovered`
- `backgroundColor`
- `labelBorderDisabled`

## Understanding styles

After evaluating tokens, the tokens are passed to a `style` function.
The `style` function should return an object which can be rendered by
the CSS renderer chosen for the design system. Likely CSS renderers
include `Fela`, `mergeStyles`, and `JSS`.

Example targeting `JSS`:

```javascript
const styles = (tokens: MyComponentTokens) => {
  return {
    root: {
      backgroundColor: tokens.backgroundColor,
      '&:hover': {
        backgroundColor: tokens.backgroundHoverColor
      }
    },
    widget: {
      borderColor: tokens.borderColor
    }
  };
}
```

## Understanding slots

Components should define a set of logical elements that are reasonable
to replace. Additionally, sensible defaults should be provided. Slots
provide an opportunity for callers to late-bind sections for
replacement.

TODO: examples of more slots

## Writing the base component

Any functional component can be used with `createComponent`. However, there are
several conventions that should be respected in order to make the user
experience predictable.

A good base component deviates from a run-of-the-mill component in 3
ways:

- It should have no built-in opinion of styling. When styled via
  `createComponent`, class names will be passed in via `slotProps` to provide
  styling.
- It accepts a prop named `slots`, which define the component to use
  for subcomponents.
- It accepts a prop named `slotProps`, which will be handed off to
  subcomponents.

### Slots

TODO: Describe how to interact with slots

### Slot Props

TODO: Describe how to interact with slotProps

### Building in practice

A simple base component that renders a button might look like the
following:

```javascript
interface Props {
  slots;
  slotProps;
  children;
  onClick;
}
const BaseButton: React.FunctionComponent<Props> = (props: Props) => {

  // First, define the slots
  // define `Root` as a const which renders the root.
  // Default to a button element.
  const { root: Root = 'button' } = props.slots || {};

  // Break out slot props to be passed to various components.
  // Mix in the props specified directly in props.
  const { root: rootProps } = props.slotProps || {};

  const resolvedRootProps = { ...rootProps, onClick: props.onClick };

  // Finally, render the component
  return <Root {...resolvedRootProps}>{props.children}</Root>
}
```

As components grow and become more complex, it is expected that hooks
will be developed to resolve state and intelligently merge `props` into
`slotProps`.

## Conformance

TODO: Describe how to run conformance tests to make sure that base
components appropriately react to theme changes.
