---
# System prepended metadata

title: Future of theming blog post

---

# Future of theming blog post


We should be thinking about how we want to communicate any big changes
in various documentation channels. Theming/styling will be at least one
big blog post, and the story should be clear about how users will move
forward.

Perf
----

Performance improvement is one of the big goals in Fabric 8.

### Styles as a function of props

Many css-in-js libraries allow you to make the css dynamic as a function of props. In practice, this leads to significant performance penalties. Consider this:

```
<Button styles={ p => { root: p.disabled ? p.disabledBackgroundColor : p.backgroundColor } } />  
```

Perf penalty 1: Everytime the Button renders, the styles function needs to be evaluated.

Perf penalty 2: After resolution, the styles are passed to the styling system, which needs to generate a hash of the object to identify if the rule has been registered.

Perf penalty 3: If the hash is missing for a given style object, the rule must be injected into the system.

We've tried to improve perf in Fabric 7 by building a graph of props values that equal the result of classnames. This means rendering 1000 buttons with the same props would evaluate the classnames 1 time, but it is far from perfect and super abusable:

1. Things which mutate constantly create unlimited classnames.

2. The graph is built from our "style props" which is a subset of user props. We assume the style props are ALWAYS provided, in the same order. But object props, while seemingly always in the same order, are not guaranteed to iterate the same order when read.

#### What this means in Fabric 8:

Currently in Fabric 7, we support `IStyleFunctionOrObject` which represents a style function 

```jsx
p => { part: { ...rules } } 
```

or an object 

```jsx
{ part: { ...rules } }
```

We are proposing two major changes:

1. The `props` of a component will never be used as an input to styling. Instead, the style set will include classnames which are injected.

2. The only parameter passed into the styles function will be the theme. The theme does not change from component to component, so it makes a great cache key. If the theme does change we can invalidate the entire stylesheet and build it again.


### Inline styled tokens going away

Style tokens make it hard to imprint CSS on the page once and exactly
once. Forcing token use through the `styled` or `compose` helpers makes
it possible to guarantee better performance.

```jsx
/* NO! */
// requires styles, makes perf optimizations very difficult
<Button styles={{ background: 'red' }} />

/* YES! */
const RedButton = styled(
  Button, 
  { 
    tokens: { 
      'boxFillChecked': 'red' 
    } 
  }
);
```

Goals
=====

```jsx

<HEAD>
   <style data-type="Button">...</style>
   <style data-type="ButtonInline">...</style>
</HEAD>

const redStyles = { 
  root: { background: 'red'},
  rootDisabled: theme => {},
  container: {
    '$rootDisabled &': {}
  },
};

<Button styles={{ root: { background: ... } }} />

const RedButton = composed(Button, {
  name: 'RedButton',
  tokens: {
    background: 'red'
  },
  
  default: {
    overrides: {
      hovered: {},
    }
  }
});

```

## Styling does not depend on props; only on theme and tokens.

All permutations of classes are generated


## Tokens

In order to make the theming/styling story a marked improvement on the
existing system, there are several goals:

Creating a base component does not have a dependency on the styling system
--------------------------------------------------------------------------

i.e. a themeless base package exists, not influcenced by a design team

Creating a styled component DOES add a dependency on a styling system
---------------------------------------------------------------------

A developer should only need to add 1 package to a `package.json` in
order to start using Fabric components.

Focus on composability
----------------------

Where theming/styling is a function of composition.

### P1 - Tokens should allow a 1-off that allows user to override a specific aspect

``` jsx
const RedButton = styled(Button, { tokens: { 'boxFillChecked': 'red' } });
```

`RedButton` is an example - it\'s easy to create and re-use.

### P1 - Universally replace a component with a new version of a component

For example: I have a `FastIcon` and I want to replace **all** instances
of `Icon` with my new `FastIcon`. How do I do this?

### P2 - Slots/Themes - should allow a theme to specify a new component for a slot

For example: An app might want to flight a change where a button use a
`FastIcon` for a specific set of users or inside a specific region of
the view.

# Components

There are a few dicsussions/proposals in flight at the moment

## Styled helper, composed helper

Currently a PR open by Mak for `compose`.

### Styled helper

manages library-specific logic with recomposibility in mind

### Composed

manages slots, slotProps, state, and view with recomposibility in mind

### Pros

1.  Can recompose and generate new typings at the same time.

### Cons


Styled helper, JSX slots w/ prop parsing helper
-----------------------------------------------

Currently a code sandbox (+ forks) by David.

### Styled helper

manages library-specific logic with recomposibility in mind

### JSX slots w/ prop parsing helper

### Pros

1.  View, state, and slotProps are in 1 function, easy to understand

### Cons

1.  Recomposing view or state requires redefining a function
    (potentially nested in a library)

2.  Providing slot overrides does not modify typings.

Next Steps
==========

In order to decide on an API we can use moving forward, we need to
rapidly decide on criteria we will use to make a decision and implement
that decision.

We should take the existing `composed` PR that Mak has open, add the
ability to mix in theming, then proceed to build a button component
using:

-   a theme-agnostic base button
-   a msft \"design system\" implementation
-   a msft design system aware button

Once this button exists, we will compare ergonomics and perf against the
currently shipping button and the experimental button and figure out the
path foward.

# Example of ideal implementation

```jsx
// In @uifabric/react-base
import { composed } from '@uifabric/react-composed'
  const BaseButton = composed({
    name,
    state,
    view,
    slots,
    slotProps
  });

// In react-composed-jss
import { composed } from '@uifabric/react-msft-composed';

import jss from 'jss';

export const composedJss = composed.extend({
  /* compose options to extend it to support style/token/theme solution */
  process: () => {}
})

// in @uifabric/react-msft-jss
import { composed } from '@uifabric/react-composed-jss';
import { designSystem } from '@uifabric/msft-design-system';

export const ButtonMsft = composed(BaseButton, {
  styles: {
    root: {
      '$foo &': {}
    },
    foo: {},
  },
  tokens: {}
});

// in @uifabric/react-msft-css
// import { composed } from 
import { composed } from '@uifabric/react-composed-css';
import { designSystem } from '@uifabric/msft-design-system';
import styles from 'Button.scss';

export const ButtonMsft = composed(BaseButton, {
  classNames: styles,
  tokens: {}
});
```
















