react-overrides
v1.4.0
Published
Helper for create reusable components through Overrides Pattern
Downloads
73
Readme
🔮 react-overrides
Pass props to internal elements of React component by passing overrides
prop.
export const PrimaryButton = props => (
<CommonButton
{...props}
overrides={{
Container: {
props: {
className: "primary_button__container", // pass className to Container element of CommonButton
"aria-role": "button" // pass ARIA attribute
}
},
Text: {
component: BigText // replace element component to BigText
}
}}
/>
);
Where CommonButton
was made with react-overrides
:
import o from "react-overrides";
export const CommonButton = props => (
<Container {...o} onClick={props.onClick}>
<Text {...o}>{props.children}</Text>
</Container>
);
Try at CodeSandbox:
Why
There is a need for pass props to elements, or replace his component. Here's some examples:
- You create UI library, and want to provide customization abilities for components. Base UI library used this approach.
- You need unified way to pass any props (for example, ARIA attributes) to common component elements.
Installation
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"]
}
Usage
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"
}
}
}} />
}
Replace internal components
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
}
}} />
}
Access to individual props
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>
);
};
Flow support
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
}
}
}}
/>
);
};
Acknowledgements
This library inspired by article Better Reusable React Components with the Overrides Pattern.