import Layout from "../../components/layout";

import Example from "../../components/example";
import Overrides from "../../components/overrides";
import { StatefulSelect, TYPE } from "baseui/select";
import { StatefulList } from "baseui/dnd-list";
import * as ListExports from "baseui/dnd-list";
import { Notification } from "baseui/notification";

import DndListExample from "examples/dnd-list/overrides_short.tsx";
import DndListExampleStyle from "examples/dnd-list/overrides_style.tsx";
import DndListExampleStateProps from "examples/dnd-list/overrides_state_props.tsx";
import DndListExampleSubcomponent from "examples/dnd-list/overrides_whole_subcomponent.tsx";
import SelectTagExample from "examples/select/overridden-tag.tsx";
import DatePickerComponentExample from "examples/datepicker/with-callback-overrides.tsx";

export default Layout;

# Understanding overrides

<Notification
  overrides={{
    Body: { style: { width: "auto" } },
  }}
>
  By the end of this guide, you'll learn the concept of overrides in Base Web
  and the ways you can use them to change the look or the behavior of
  components.
</Notification>

Base Web is a set of reusable React components that implements the Base Web design language and can be used in 2 ways:

- **To build an application** that fully adopts the Base Web design language, you import and use Base Web components out of the box
- **To build a new design system** inherited from the Base, you take Base Web components and customize them through the overrides mechanism

If you’re building an application using the Base Web design language (the first scenario), you should avoid further customization. This helps to keep the design of your application consistent and makes future upgrades easier. **Overrides is an escape hatch that should be used only with great caution!**

## Subcomponents

Base Web components typically consist of many subcomponents. Let's use `baseui/dnd-list` as an example:

<DndListExample />

This component is very self-contained, and you can load it through a single import:

```jsx
import { StatefulList } from "baseui/dnd-list";

export default () => (
  <StatefulList
    initialState={{
      items: ["Item 1", "Item 2", "Item 3"],
    }}
  />
);
```

But as you might guess, there are multiple React components under the hood - components like `Item`, `DragHandle` or `Label`. They all come with various styles, behaviors, and attributes. We call them subcomponents.

## Introducing overrides

Overrides gives you full access to all those subcomponents and lets you override these:

- Styles of the subcomponent
- Props of the subcomponent
- The whole subcomponent

**Every Base Web component has a top-level prop called `overrides`**. It accepts a map of subcomponents and desired overrides. For example, if we want to change the `Label`'s color and add a `data-testid` attribute (props are spread over the subcomponent), we can do this:

```jsx
<StatefulList
  initialState={{
    items: ["Item 1", "Item 2", "Item 3"],
  }}
  overrides={{
    Label: {
      style: {
        color: "#892C21",
      },
      props: {
        "data-testid": "dnd-list-label",
      },
    },
  }}
/>
```

We defined `overrides.Label.style` and `overrides.Label.props` properties, and this is the result (inspect the element to see the `data-testid` attribute):

<DndListExampleStyle />

The `overrides.Label.style` property accepts a [style object](https://www.styletron.org/concepts/#style-object) or [style function](https://www.styletron.org/concepts/#style-function) since [Styletron](https://www.styletron.org) manages all Base Web styles.

> Caveat: when using `overrides.foo.style`, you’re overriding a set of existing CSS properties. **Our components always use longhand CSS properties, so should yours.** If you [mix shorthand and longhand properties](https://www.styletron.org/concepts/#shorthand-and-longhand-properties), you’ll see a warning and can run into strange behaviors.

## `$theme`

If you opt in for the [style function](https://www.styletron.org/concepts/#style-function), `overrides` provides a special prop called **`$theme`** that you can use. The `$theme` prop includes all Base Web [design constants](/guides/theming/#theme-properties). So instead of the hard-coded value `#892C21`, you can use the theme:

```jsx
<StatefulList
  initialState={{
    items: ["Item 1", "Item 2", "Item 3"],
  }}
  overrides={{
    Label: {
      style: ({ $theme }) => ({
        color: $theme.colors.negative600,
      }),
    },
  }}
/>
```

## State props

The prop `$theme` is not the only variable that you can use in your style function. Most subcomponents get various state props. For example, the `Label` comes with these:

- `$isDragged: boolean` - `true` if the list item is dragged
- `$isSelected: boolean` - `true` if the list item is selected (space key-press)
- `$isRemovable: boolean` - `true` if the list item is removable
- `$value: React.Node` item's value
- `$index: number` item's index

Let's use `$isDragged` to change the label color when dragged:

```jsx
<StatefulList
  initialState={{
    items: ["Item 1", "Item 2", "Item 3"],
  }}
  overrides={{
    Label: {
      style: ({ $theme, $isDragged }) => ({
        color: $isDragged ? $theme.colors.primary : $theme.colors.accent400,
      }),
    },
  }}
/>
```

The result is that the label turns black when it's dragged:

<DndListExampleStateProps />

## Exploring overrides

Almost every Base Web component has multiple overrides. How can you learn what's available to you? Every component page has the `Style Overrides` section at the top. It lists all overridable subcomponents and highlights each one of them once activated. Using this editor, you can also change the style properties of each override, so you can see instantly how the modified components would look.

If you’re interested in which state props your style functions can use, click on "Toggle shared props" in the overrides:

<img src="/images/react-view-overrides.png" width="100%" />

## Override nested components

Every Base Web component exposes the `override` prop. When one Base Web component uses another Base Web component internally, we have access to a new, powerful pattern: **nested overrides**.

The idea is to use a component's `overrides` prop to access a nested component and pass this nested component an `overrides` prop of its own. You end up with a _nested_ structure like so:

```jsx
<Foo
  overrides={{
    Boo: {
      props: {
        overrides: {
          // pass "nested" overrides to the inner "Boo" component
        },
      },
    },
  }}
/>
```

This is a very reliable method for customizing deeply nested components. It is possible because everywhere a Base Web component uses another Base Web component, that ‟parent” component will expose an `overrides` property for the ‟child” component. In theory, you could nest overrides as many levels deep as necessary to customize something.

```jsx
<Foo
  overrides={{
    Boo: {
      props: {
        overrides: {
          Moo: {
            props: {
              overrides: {
                Zoo: {
                  props: {
                    overrides: {
                      Goo: () => "hey mom!",
                    },
                  },
                },
              },
            },
          },
        },
      },
    },
  }}
/>
```

In this example, we use 4 nested overrides to replace the `Goo` component. We do this without affecting the 4 components above `Goo`. We've avoided having to re-implement layers and layers of logic, and, because the interface is consistent, you can focus on _where_ you want to drop in, rather than _how_ to do it.

If you find the exact syntax of this technique a little difficult to recall, try instead to remember that every Base Web component exposes an `overrides` prop and that every nested Base Web component is made accessible as an `overrides` property in the top-level component.

The path always follows this pattern:

> ComponentA > overrides > ComponentB > props > overrides

### A more practical example

Here is the default multi-select option for Base Web:

<StatefulSelect
  multi
  type="search"
  options={[
    { label: "Atlanta", id: "ATL" },
    { label: "Baltimore", id: "BWI" },
    { label: "Chicago", id: "ORD" },
    { label: "Denver", id: "DEN" },
  ]}
  initialState={{
    value: [{ label: "Atlanta", id: "ATL" }],
  }}
/>

Let's change the way the selected values appear.

The first step is to identify _what_ we want to override. In this case, we want to change the selected values for a multi-select. Let's check out the [`overrides` inspector for Select](/components/select/#overrides). Looking through the list of possible overrides, we see there is a promising `Tag` property.

We can [reference the documentation for Tag](/components/tag/#overrides) to see what overrides are available.

We’ve identified a nested Base Web component that’s accessible via overrides. Now we can apply some nested overrides to customize things:

<Example path="select/overridden-tag.tsx">
  <SelectTagExample />
</Example>

Notice the nested override pattern here:

> StatefulSelect > overrides > Tag > props > overrides

Once we have access to the nested `Tag`, we can override the styles for the `Root`, `Text`, `Action` and `ActionIcon`, changing the colors to a few lovely shades of purple.

## Override the entire subcomponent

> This is a very advanced technique and rarely needed. If you go down this path, you might also need to inspect our source code to fully understand all behaviors that subcomponents should/can implement.

So far we demonstrated how to override styles or add additional props, but you can also completely replace subcomponents. This means you can alter the behavior and appearance of all Base Web components. For example, we can enhance our textual label and add a cloning functionality:

```jsx
import * as React from "react";
import { List, arrayMove } from "baseui/dnd-list";

export default class Example extends React.Component {
  state = {
    items: ["Car", "Truck", "Bike", "Skateboard"],
  };
  render() {
    return (
      <List
        items={this.state.items}
        onChange={({ oldIndex, newIndex }) =>
          this.setState((prevState) => ({
            items: arrayMove(prevState.items, oldIndex, newIndex),
          }))
        }
        overrides={{
          Label: {
            component: ({ $value }) => (
              <div style={{ flexGrow: 1 }}>
                {$value}{" "}
                <button
                  onClick={() =>
                    this.setState((prevState) => ({
                      items: prevState.items.concat([`${$value} clone`]),
                    }))
                  }
                >
                  Clone
                </button>
              </div>
            ),
          },
        }}
      />
    );
  }
}
```

The result:

<DndListExampleSubcomponent />

Note that we lost the original label styling since we replaced the whole label subcomponent. If you still want to reuse or compose the original subcomponent you can import it:

```js
import { StyledLabel } from "baseui/dnd-list";
```

The named import always matches the override key with an addition of `Styled` prefix. Following 2 examples yield the exact, same result since this is how Base Web components are implemented underneath:

```jsx
<StatefulList
 initialState={{items: ['A', 'B', 'C']}}
 overrides={{Label: StyledLabel}}
/>

<StatefulList
 initialState={{items: ['A', 'B', 'C']}}
/>
```

### Enhancing and merging component props

This example demonstrates a complex scenario where component props are wrapped and enhanced but the original functionality is retained.

<Example path="datepicker/with-callback-overrides.tsx">
  <DatePickerComponentExample />
</Example>

This technique gives you a ridiculous amount of flexibility. However, with great power comes great responsibility. We might not be able to effectively support you if you run into issues, and upgrades to future versions of Base Web can be complicated. If you need to change components behavior this way, you should first [ask the maintainers](https://github.com/uber/baseweb/issues) of Base Web. We might add your feature through an official API instead so you don't need to use this override.

To learn more about how overrides work internally, check out article [Better Reusable React Components with the Overrides Pattern](https://medium.com/@dschnr/better-reusable-react-components-with-the-overrides-pattern-9eca2339f646).
