Skip to content

Introducing CSS cascading to React components with first-class Typescript support right out of the box.

License

Notifications You must be signed in to change notification settings

codyduong/react-cascade-component

Repository files navigation

downloads per/month gzip size module formats: umd, cjs, esm Code Coverage

React-Cascade-Component

Introducing CSS cascading to React components with first-class Typescript support right out of the box.

DRY out your code. Repeat yourself less with less hassle.

Installation

npm yarn
npm install react-cascade-component yarn add react-cascade-component

Example Use Case

import Cascade from 'react-cascade-component'; const App = () => { const onClickHandler: React.MouseEventHandler<HTMLButtonElement> = (e) => { alert(`Button ${e.currentTarget.id} was clicked!`); }; return ( <Cascade cascadeTo="button" cascadeProps={{ onClick: onClickHandler }}> <div /> <div /> <button id="1" /> <button id="2" /> <button id="3" /> </Cascade> ); };

Cascade by default is a div element but can be of any JSX.IntrinsicElement by setting the as prop value or using Cascade.[JSX.IntrinsicElement] .

<Cascade as="span">{/* ... */}</Cascade> <Cascade.span>{/* ... */}</Cascade.span>

API

prop type examples

as

Specifies what <Cascade/> is rendered as. Defaults to div
undefined

keyof JSX.IntrinsicElement

React.JSXElementConstructor<any>
"div"

"span"

MyCustomComponent

cascadeTo

Specifies which child elements cascadeProps is sent to. If null will send cascadeProps to all children elements. If undefined will default to the outer cascadeTo if inside another <Cascade> component. If not, it will send to all children elements.
undefined

null

keyof JSX.IntrinsicElement

React.JSXElementConstructor<any> (keyof JSX.IntrinsicElement | React.JSXElementConstructor<any>)[]

"div"

["span", "div"]

MyCustomComponent

['span', MyCustomComponent]

cascadeProps

The `props` to cascade to child elements
any1 {"className": "foobar", "customKey": "customValue"}

absorbProps

Whether or not the <Cascade> will absorb the properties itself, or simply pass it on. Defaults to true
boolean true false

...rest

Any other properties to be used by <Cascade>
JSX.IntrinsicElement[typeof as] Valid other properties may be ref className id and more

1 - The is not technically true, but practically true. It has a type dependent on cascadeTo, and will have type inference if cascadeTo is provided

Demos

CascadeTo Callback

The <Cascade> component has a callback parameter on cascadeTo which means you can specify handling, by default the callback is (callbackProps, originalProps) => {...callbackProps, ...originalProps}, ie. a shallow merge.

<Cascade cascadeTo={[ ['button', (c, o) => ({ ...c.buttonProps, ...o })], [MyCustomComponent, (c, o) => ({ ...c.customProps, ...o })], ]} cascadeProps={{ buttonProps: { onClick: onClickHandler, }, customProps: { className: 'foobar' } }} > <button /> <div /> <MyCustomComponent /> </Cascade>

You can also specify a function instead:

<Cascade cascadeTo={(t, c, o) => { if (t === 'button') { return {...c.buttonProps, ...o} } if (t === MyCustomComponent) { return {...c.customProps, ...o} } }} cascadeProps={{ buttonProps: { onClick: onClickHandler, }, customProps: { className: 'foobar' } }} > <button /> <div /> <MyCustomComponent /> </Cascade>

Nested Cascades

The <Cascade> component can pass through to each other. By default it will both absorb and pass properties. Nested <Cascade> components will cascadeTo the same constrained types. <Cascade absorbProps={false} /> will disable absorbing props but will still pass through through properties.

<Cascade className="foo" cascadeProps={{ className: 'bar' }}> <Cascade className="bang" cascadeTo={[Cascade, 'span']} > <Cascade.span> {/* Cascade.span !== 'span' */} <div /> <div /> <span /> <label /> </Cascade.span> <Cascade cascadeTo={null} > <span /> {/* className="bar" */} <label /> {/* className="bar" */} </Cascade> <Cascade> {/* className="bar" */} <span /> {/* className="bar" */} <label /> </Cascade> <Cascade /* className=undefined */ absorbProps={false} cascadeTo="label" > <span /> <label /> {/* className="bar" */} </Cascade> <div> <span /> <label /> </div> </Cascade> </Cascade>;

Alternatives

If you are simply using react-cascade-component as a means to transfer props deeply in your component, instead consider using React's built-in useContext .

Contribute

Contributions are welcome!

License

Licensed under the MIT License, Copyright © 2023-present Cody Duong.

See LICENSE for more information.

About

Introducing CSS cascading to React components with first-class Typescript support right out of the box.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published