Let's create CommonButton
component with react-overrides
:
import o from "react-overrides";
export const CommonButton = props => (
<Container {...o} onClick={props.onClick}>
<Text {...o}>{props.children}</Text>
</Container>
);
Next, we can pass props to internal elements of CommonButton
by passing overrides
prop:
export const LinkButton = props => (
<CommonButton
{...props}
overrides={{
Container: { // 'Container' element of CommonButton
props: {
as: "a", // say the component to display itself as <a> tag. Typical for CSS-in-JS solutions.
href: props.href // add href attribute to element
}
}
}}
/>
);
So we extend the CommonButton
by creating a LinkButton
that has link behavior.
Try at CodeSandbox:
It is also possible to replace the entire component:
export const LinkButton = props => (
<CommonButton
{...props}
overrides={{
Text: {
component: BigText
}
}}
/>
);
<img src="https://lessmess.agency/badges/sponsored_by_lessmess.svg" alt="Sponsored by Lessmess" width="236" height="54">
There is a need for pass props directly to elements, or replace his component. Here's some examples of when you need it:
Install core package and babel plugin with yarn:
yarn add react-overrides
yarn add babel-plugin-react-overrides --dev
Or with npm:
npm i react-overrides --save
npm i babel-plugin-react-overrides --save-dev
Further, add react-overrides
to your .babelrc
configuration:
{
"plugins": ["babel-plugin-react-overrides"]
}
Create extendable component by passing the default export
from react-overrides
package to the component to be extended.
Example:
import React, {useState} from "react";
import o from "react-overrides";
import {Container, Value, OptionsContainer, Option} from "...";
export const Select = (props) => {
const {opened, setOpened} = useState(false);
return <Container {...o} onClick={() => setOpened(!opened)}>
<Value {...o}>{props.currentValue}</Value>
{opened && <OptionsContainer {...o}>
{props.values.map(({label, id}) => (
<Option {...o} onClick={() => props.onSelect(id)} key={id}>{label}</Option>
))}
</OptionsContainer>}
</Container>
};
Extend with component through passing props of internal component:
import React from "react";
import {Select} from "./Select"
const BigOptionSelect = (props) => {
return <Select {...props} overrides={{
Option: {
props: {
className: "big-option-select__option",
"aria-role": "button"
}
}
}} />
}
You can replace the internal component with a custom one:
import React from "react";
import {Select} from "./Select"
import {FancyGrid} from "./fancy-grid";
const FancyGridSelect = (props) => {
return <Select {...props} overrides={{
OptionsContainer: {
component: FancyGrid
}
}} />
}
import React from "react";
import o from "react-overrides";
import c from "classnames";
import "./button.scss";
const Button = props => {
const Container = (props) => <button {...props) />;
const Text = (props) => <span {...props) />;
return (
<Container {...o} className={c("button", o.className)} onClick={props.onClick}>
<Text className={c("button__text", o.className)} />
{props.children}
</Text>
</Input>
);
};
You can use ExtractOverrides
type props helper for infer overrides prop type from components types.
// @flow
import * as React from "react";
import o, { type ExtractOverridesProps } from "react-overrides";
const Option = (props: { a: 1 | 2, b: string }) => {
return <div>{props.b + 2 * props.a}</div>;
};
const Container = (props: { children?: React.Node }) => {
return <div>{props.children}</div>;
};
const OverridableProps = {
Option,
Container
};
type TOverridesProps = ExtractOverridesProps<typeof OverridableProps>;
const Select = (props: { overrides: TOverridesProps }) => {
return (
<Container {...o}>
{/* For access to individual prop used o().<prop>, o.<prop> throw Flow error */}
<Option {...o} a={1} b={o().b || "x"} />
</Container>
);
};
const OverridedSelect = () => {
return (
<Select
overrides={{
Option: {
props: {
a: 1,
}
}
}}
/>
);
};
// throw flow error:
const OverridedSelectWrong = () => {
return (
<Select
overrides={{
Option: {
props: {
a: 3
}
}
}}
/>
);
};
This library inspired by article Better Reusable React Components with the Overrides Pattern.
Thanks @ai for review the documentation.