From a307f8df5a60543c2d33c1355caabf5bbff8ffce Mon Sep 17 00:00:00 2001 From: Ashwin kumar Date: Mon, 24 May 2021 12:08:06 +0530 Subject: [PATCH 1/5] Add blog post - react-compound-components --- .../2021-5-25-React-compound-compnents.md | 250 ++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 posts/react-compound-components/2021-5-25-React-compound-compnents.md diff --git a/posts/react-compound-components/2021-5-25-React-compound-compnents.md b/posts/react-compound-components/2021-5-25-React-compound-compnents.md new file mode 100644 index 0000000..f8c4ef3 --- /dev/null +++ b/posts/react-compound-components/2021-5-25-React-compound-compnents.md @@ -0,0 +1,250 @@ +--- +templateKey: "blog-post" +title: "React compound components (Hooks + typescript)" +date: 2021-05-25 +featuredpost: false +description: >- + This article talks about what are compound components and how to build an accordion component using the concept of compound components. +keywords: +- reactjs +- Compound-components +- Hooks +- Typescript +link: /react-compound-components +category: +- Tutorial +author: Ashwin kumar +tags: +- react js +- reactjs +- typescript +- compound components +- build accordion component using compound components +--- + +**Compound Components** are an advanced and great pattern which you can use to create the meta component. It gives your components more flexibility. It is little difficult to understand the concept initially, But believe me, if you get a hold of it you will love building the components using compound components pattern + +## What are compound components? + +The compound components are a set of two or more components that work together to accomplish a specific task. The set of components will share an implicit state to communicate between them. + +> Think of compound components like the select and option elements in HTML. Apart they don’t do too much, but together they allow you to create the complete experience. — Kent C. Dodds + +```jsx + +``` + +In the above example, when you click on an option in the select component, select knows which option you clicked. The select and the option share the state between them and update the selected option state on their own, we don’t need to explicitly configure them. + +## Compound Components in Action + +In this post, we’ll be building an Accordion component using compound components. + +You can check out the [Code sandbox link](https://codesandbox.io/s/interesting-wildflower-wj3iy) for the final demo of the accordion component. + +The accordion component will have four components. + +1. **Accordion** - The outer wrapper component of the Accordion component. This is the root component of the Accordion component. +2. **AccordionItem** - The component that allows us to define each accordion item. Each AccordionItem will have its AccordionButton and AccordionPanel components. +3. **AccordionButton** - The header for the Accordion component.On clicking the accordion button will open the corresponding accordion panel. +4. **AccordionPanel** - The panel for the accordion. This will hold the content of each accordion item. + +We are going to create the above mentioned components one by one and also let's see how we can create the link between them. +Let's start with Accordion component. Accordion component will wrap all other necessary components and will maintain the state that is to be shared among all the other components + +```tsx +const Accordion: React.FC<{ + children: ReactNode | ReactNode[]; + className?: string +}> = ({ children, className }) => { + const [activeItem, setActiveItem] = useState(""); + // function to update the active item + const changeActiveItem = useCallback( + (value) => { + if (activeItem !== value) setActiveItem(value); + }, + [setActiveItem, activeItem] + ); + + return
{children}
+} +``` + +we had created the accordion component, now we need to pass or share the state and the function to update the state to its children. To achieve this, we are going to use the **React Context**. If you are not familiar with React context, please refer [https://reactjs.org/docs/context.html](https://reactjs.org/docs/context.html). Iam not gonna explain about react context here, but i will give you a hint about react context. + +> Context provides a way to pass data through the component tree without having to pass props down manually at every level. + +Now let's add context to our accordion component. + +```tsx +import { createContext, useContext } from "react"; + +// Creating the context for the Accordion. +export const AccordionContext = createContext<{ + activeItem: string; + changeSelectedItem: (item: string) => void; +}>({ activeItem: "", changeSelectedItem: () => {} }); + +export const useAccordionContext = () => { + const context = useContext(AccordionContext); + if (!context) { + throw new Error("Error in creating the context"); + } + return context; +}; +``` + +After creating the context, we need to provide values to the context, it is done by **Context.Provider** element. The values refers to the data that is to be shared among all the components in the accordion. The **Provider** component accepts a value prop to be passed to consuming components that are descendants of this Provider. One Provider can be connected to many consumers. + +```tsx +const Accordion: React.FC<{ + children: ReactNode | ReactNode[]; + className?: string; +}> = ({ children, className }) => { + const [activeItem, setActiveItem] = useState(""); + + const changeActiveItem = useCallback( + (value) => { + if (activeItem !== value) setActiveItem(value); + }, + [setActiveItem, activeItem] + ); + return ( + +
{children}
+
+ ); +}; + +export default Accordion; +``` + +In the accordion, we need to share the activeItem and changeSelectedItem to all the other components, so we are passing those two to the value of accordion context provider. Now We had built the root accordion component and also we have provided the values to the context. Let's build the remaining components and we are going to use the values consumed from the context and make the accordion component work as a whole. + +```tsx +// AccordionItem component +export const AccordionItem: React.FC<{ + children: ReactNode[]; + label: string; +className?: string; +}> = ({ children, label, className }) => { + const childrenArray = React.Children.toArray(children); + + // label is used to distinguish between each accordion element. + // Adding the label prop to the children of accordionItem along with other props. + const accordionItemChildren = childrenArray.map((child) => { + if (React.isValidElement(child)) { + return React.cloneElement(child, { + ...child.props, + label + }); + } + return null; + }); + return
{accordionItemChildren}
; +}; +``` + +```tsx +// AccordionButton component +export const AccordionButton: React.FC<{ + children: ReactNode; + label?: string; + className?:string +}> = ({ label, children, className }) => { + const { changeSelectedItem } = useAccordionContext(); + const accordionButtonClickHandler = useCallback(() => { + changeSelectedItem(label || ""); + }, [changeSelectedItem, label]); + + return ( +
+ {children} +
+ ); +}; +``` + +```tsx +// AccordionPanel component +export const AccordionPanel: React.FC<{ + children: ReactNode; + label?: string; + className?:string +}> = ({ children, label, className }) => { + const { activeItem } = useAccordionContext(); + const panelStyles = [ + "accordion-panel", + label === activeItem ? "show-item" : "hide-item", + className + ].join(" "); + + return
{children}
; +}; +``` + +We have done with creating all other components. Let's see what we have done. + +- In the Accordion-item, label prop is used to differentiate between different accordion items. The label prop will be required in the accordionButton and accordionPanel components, so we are adding label prop to the accordionItem children along with the other props. +- We are using the **useAccordionContext** in the AccordionPanel and AccordionButton. That is how we get the data that is being provided from the Accordion component. +- We use changeSelectedItem in the AccordionButton component to update the active item when the button is clicked. +- We use activeItem in the AccordionPanel component whether show the content or hide the content + +Now we had built the accordion component completely, let's see how we can use the Accordion component + +```tsx +import { + Accordion, + AccordionButton, + AccordionItem, + AccordionPanel +} from "./components/accordion"; + +export default function App() { + return ( +
+ + + React + +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. +

+
+
+ + Angular + +

+ Excepteur sint occaecat cupidatat non proident, sunt in culpa qui + officia deserunt mollit anim id est laborum. +

+
+
+ + Javasciprt + + Duis aute irure dolor in reprehenderit in voluptate velit esse + cillum dolore eu fugiat nulla pariatur. + + +
+
+ ); +} +``` +Yayyy!!! We had built the accordion component using the compound components. + + We can also build the same accordion component using render props method but there are many limitations to style the inner components (AccordionButton & AccordionPanel) , we need to pass props like renderAccordionButton, buttonClassName for the AccordionButton and we need separate props for AccordionItem and also AccordionPanel. + + Look at the accordion component now, it looks clean, you can style each and every component of Accordion using its respective component. In future, if you want to have buttonColour for the AccordionButton component, you can just add that prop to the AccordionButton alone and not to the outer accordion component. + + Feel free to try it and check out the component in [code sandbox](https://codesandbox.io/s/interesting-wildflower-wj3iy). I hope you had understood the compound components and how to use them. \ No newline at end of file From 232bcf7c3e5eec46e93ba94635e7bf985dfbcbf6 Mon Sep 17 00:00:00 2001 From: Ashwin kumar Date: Tue, 25 May 2021 11:22:15 +0530 Subject: [PATCH 2/5] Fix : typography grammer mistakes --- .../2021-5-25-React-compound-compnents.md | 191 +++++++++--------- 1 file changed, 99 insertions(+), 92 deletions(-) diff --git a/posts/react-compound-components/2021-5-25-React-compound-compnents.md b/posts/react-compound-components/2021-5-25-React-compound-compnents.md index f8c4ef3..d7181fc 100644 --- a/posts/react-compound-components/2021-5-25-React-compound-compnents.md +++ b/posts/react-compound-components/2021-5-25-React-compound-compnents.md @@ -1,28 +1,28 @@ --- templateKey: "blog-post" -title: "React compound components (Hooks + typescript)" +title: "How to build a simple Compound component using ReactJS hooks" date: 2021-05-25 featuredpost: false description: >- - This article talks about what are compound components and how to build an accordion component using the concept of compound components. + This article explains with an example what compound components in react are . How to build a compound component with a tutorial to build accordion. keywords: -- reactjs -- Compound-components -- Hooks -- Typescript + - reactjs + - Compound-components + - Hooks + - Typescript link: /react-compound-components category: -- Tutorial + - Tutorial author: Ashwin kumar tags: -- react js -- reactjs -- typescript -- compound components -- build accordion component using compound components + - react js + - reactjs + - typescript + - compound components + - build accordion component using compound components --- -**Compound Components** are an advanced and great pattern which you can use to create the meta component. It gives your components more flexibility. It is little difficult to understand the concept initially, But believe me, if you get a hold of it you will love building the components using compound components pattern +**Compound Components** are an advanced and very useful pattern. They can be used to create meta components. They are slightly counter intuitive, but trust me, once you get a hang of it, you will love building components using the compound components pattern. ## What are compound components? @@ -32,10 +32,10 @@ The compound components are a set of two or more components that work together t ```jsx ``` @@ -43,153 +43,154 @@ In the above example, when you click on an option in the select component, selec ## Compound Components in Action -In this post, we’ll be building an Accordion component using compound components. - -You can check out the [Code sandbox link](https://codesandbox.io/s/interesting-wildflower-wj3iy) for the final demo of the accordion component. +we will build an Accordion component using the compound component pattern. The accordion component will have four components. -1. **Accordion** - The outer wrapper component of the Accordion component. This is the root component of the Accordion component. +1. **Accordion** - The outer wrapper component of the Accordion component. This is the root component of the Accordion component. 2. **AccordionItem** - The component that allows us to define each accordion item. Each AccordionItem will have its AccordionButton and AccordionPanel components. 3. **AccordionButton** - The header for the Accordion component.On clicking the accordion button will open the corresponding accordion panel. 4. **AccordionPanel** - The panel for the accordion. This will hold the content of each accordion item. -We are going to create the above mentioned components one by one and also let's see how we can create the link between them. -Let's start with Accordion component. Accordion component will wrap all other necessary components and will maintain the state that is to be shared among all the other components +We are going to create the above mentioned components one by one and also let's see how we can create the link between them. +Let's start with Accordion component. Accordion component will wrap the other components. It will also maintain shared state with other components. In this case the selected accordion item (active item) ```tsx const Accordion: React.FC<{ - children: ReactNode | ReactNode[]; + children: ReactNode | ReactNode[] className?: string }> = ({ children, className }) => { - const [activeItem, setActiveItem] = useState(""); + const [activeItem, setActiveItem] = useState("") // function to update the active item - const changeActiveItem = useCallback( - (value) => { - if (activeItem !== value) setActiveItem(value); + const changeActiveItem = useCallback( + value => { + if (activeItem !== value) setActiveItem(value) }, [setActiveItem, activeItem] - ); + ) return
{children}
} -``` +``` -we had created the accordion component, now we need to pass or share the state and the function to update the state to its children. To achieve this, we are going to use the **React Context**. If you are not familiar with React context, please refer [https://reactjs.org/docs/context.html](https://reactjs.org/docs/context.html). Iam not gonna explain about react context here, but i will give you a hint about react context. +We have created the root Accordion component. Now we need to pass down or share the state and the update state function with its children. To achieve this, we are going to use the **React Context**. If you are not familiar with React context, please refer [https://reactjs.org/docs/context.html](https://reactjs.org/docs/context.html). > Context provides a way to pass data through the component tree without having to pass props down manually at every level. Now let's add context to our accordion component. ```tsx -import { createContext, useContext } from "react"; +import { createContext, useContext } from "react" // Creating the context for the Accordion. export const AccordionContext = createContext<{ - activeItem: string; - changeSelectedItem: (item: string) => void; -}>({ activeItem: "", changeSelectedItem: () => {} }); + activeItem: string + changeSelectedItem: (item: string) => void +}>({ activeItem: "", changeSelectedItem: () => {} }) export const useAccordionContext = () => { - const context = useContext(AccordionContext); + const context = useContext(AccordionContext) if (!context) { - throw new Error("Error in creating the context"); + throw new Error("Error in creating the context") } - return context; -}; -``` + return context +} +``` -After creating the context, we need to provide values to the context, it is done by **Context.Provider** element. The values refers to the data that is to be shared among all the components in the accordion. The **Provider** component accepts a value prop to be passed to consuming components that are descendants of this Provider. One Provider can be connected to many consumers. +Lets provide values to the context using the Context.Provider element. The **Provider** component accepts a value prop to be passed to consuming components that are descendants of this Provider. One Provider can be connected to many consumers. ```tsx const Accordion: React.FC<{ - children: ReactNode | ReactNode[]; - className?: string; + children: ReactNode | ReactNode[] + className?: string }> = ({ children, className }) => { - const [activeItem, setActiveItem] = useState(""); + const [activeItem, setActiveItem] = useState("") const changeActiveItem = useCallback( - (value) => { - if (activeItem !== value) setActiveItem(value); + value => { + if (activeItem !== value) setActiveItem(value) }, [setActiveItem, activeItem] - ); + ) return (
{children}
- ); -}; + ) +} -export default Accordion; -``` +export default Accordion +``` -In the accordion, we need to share the activeItem and changeSelectedItem to all the other components, so we are passing those two to the value of accordion context provider. Now We had built the root accordion component and also we have provided the values to the context. Let's build the remaining components and we are going to use the values consumed from the context and make the accordion component work as a whole. +In the accordion, we need to share the activeItem and changeSelectedItem to all the other components, so we are passing them to the context provider which can be obtained using the the useAccordionContext custom hook (which uses the useContext hook internally). Let's build the remaining components. We are going to use the values consumed from the context and make the accordion component work as a whole. ```tsx // AccordionItem component export const AccordionItem: React.FC<{ - children: ReactNode[]; - label: string; -className?: string; + children: ReactNode[] + label: string + className?: string }> = ({ children, label, className }) => { - const childrenArray = React.Children.toArray(children); + const childrenArray = React.Children.toArray(children) // label is used to distinguish between each accordion element. // Adding the label prop to the children of accordionItem along with other props. - const accordionItemChildren = childrenArray.map((child) => { + const accordionItemChildren = childrenArray.map(child => { if (React.isValidElement(child)) { return React.cloneElement(child, { ...child.props, - label - }); + label, + }) } - return null; - }); - return
{accordionItemChildren}
; -}; -``` + return null + }) + return
{accordionItemChildren}
+} +``` ```tsx // AccordionButton component export const AccordionButton: React.FC<{ - children: ReactNode; - label?: string; - className?:string + children: ReactNode + label?: string + className?: string }> = ({ label, children, className }) => { - const { changeSelectedItem } = useAccordionContext(); + const { changeSelectedItem } = useAccordionContext() const accordionButtonClickHandler = useCallback(() => { - changeSelectedItem(label || ""); - }, [changeSelectedItem, label]); + changeSelectedItem(label || "") + }, [changeSelectedItem, label]) return ( -
+
{children}
- ); -}; -``` + ) +} +``` ```tsx // AccordionPanel component export const AccordionPanel: React.FC<{ - children: ReactNode; - label?: string; - className?:string + children: ReactNode + label?: string + className?: string }> = ({ children, label, className }) => { - const { activeItem } = useAccordionContext(); + const { activeItem } = useAccordionContext() const panelStyles = [ "accordion-panel", label === activeItem ? "show-item" : "hide-item", - className - ].join(" "); + className, + ].join(" ") + + return
{children}
+} +``` - return
{children}
; -}; -``` - We have done with creating all other components. Let's see what we have done. - In the Accordion-item, label prop is used to differentiate between different accordion items. The label prop will be required in the accordionButton and accordionPanel components, so we are adding label prop to the accordionItem children along with the other props. @@ -204,8 +205,8 @@ import { Accordion, AccordionButton, AccordionItem, - AccordionPanel -} from "./components/accordion"; + AccordionPanel, +} from "./components/accordion" export default function App() { return ( @@ -238,13 +239,19 @@ export default function App() {
- ); + ) } -``` +``` + Yayyy!!! We had built the accordion component using the compound components. - We can also build the same accordion component using render props method but there are many limitations to style the inner components (AccordionButton & AccordionPanel) , we need to pass props like renderAccordionButton, buttonClassName for the AccordionButton and we need separate props for AccordionItem and also AccordionPanel. - - Look at the accordion component now, it looks clean, you can style each and every component of Accordion using its respective component. In future, if you want to have buttonColour for the AccordionButton component, you can just add that prop to the AccordionButton alone and not to the outer accordion component. +We can also build the same accordion component using render props method. But there are limitations to style the inner components (AccordionButton; AccordionPanel). We will have to pass props like renderAccordionButton for custom button component. + +The accordion component, now looks clean. One can style every component of the Accordion using its respective component. In future, if you want to have buttonColour for the AccordionButton component, you can just add that prop to the AccordionButton itself. Not clutter the outer accordion component. - Feel free to try it and check out the component in [code sandbox](https://codesandbox.io/s/interesting-wildflower-wj3iy). I hope you had understood the compound components and how to use them. \ No newline at end of file + From 865a84983510ed7d2a0b0de8450ecae44d0e04f1 Mon Sep 17 00:00:00 2001 From: Ashwin kumar Date: Tue, 25 May 2021 11:31:13 +0530 Subject: [PATCH 3/5] Updated the link --- .../2021-5-25-React-compound-compnents.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/posts/react-compound-components/2021-5-25-React-compound-compnents.md b/posts/react-compound-components/2021-5-25-React-compound-compnents.md index d7181fc..f58a0d6 100644 --- a/posts/react-compound-components/2021-5-25-React-compound-compnents.md +++ b/posts/react-compound-components/2021-5-25-React-compound-compnents.md @@ -10,7 +10,7 @@ keywords: - Compound-components - Hooks - Typescript -link: /react-compound-components +link: /how-to-build-react-compound-components-tutorial category: - Tutorial author: Ashwin kumar From ef8c68abc9b86308496c3535b4aa3f85b18db339 Mon Sep 17 00:00:00 2001 From: Ashwin kumar Date: Tue, 25 May 2021 11:34:48 +0530 Subject: [PATCH 4/5] Renamed the label to cb-internal-label --- .../2021-5-25-React-compound-compnents.md | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/posts/react-compound-components/2021-5-25-React-compound-compnents.md b/posts/react-compound-components/2021-5-25-React-compound-compnents.md index f58a0d6..3f5609f 100644 --- a/posts/react-compound-components/2021-5-25-React-compound-compnents.md +++ b/posts/react-compound-components/2021-5-25-React-compound-compnents.md @@ -137,15 +137,15 @@ export const AccordionItem: React.FC<{ // label is used to distinguish between each accordion element. // Adding the label prop to the children of accordionItem along with other props. - const accordionItemChildren = childrenArray.map(child => { + const accordionItemChildren = childrenArray.map((child) => { if (React.isValidElement(child)) { return React.cloneElement(child, { ...child.props, - label, - }) + __cb__internal__accordion_label: label + }); } - return null - }) + return null; + }); return
{accordionItemChildren}
} ``` @@ -153,14 +153,14 @@ export const AccordionItem: React.FC<{ ```tsx // AccordionButton component export const AccordionButton: React.FC<{ - children: ReactNode - label?: string - className?: string -}> = ({ label, children, className }) => { - const { changeSelectedItem } = useAccordionContext() + children: ReactNode; + __cb__internal__accordion_label?: string; + className?: string; +}> = ({ __cb__internal__accordion_label: label, children, className }) => { + const { changeSelectedItem } = useAccordionContext(); const accordionButtonClickHandler = useCallback(() => { - changeSelectedItem(label || "") - }, [changeSelectedItem, label]) + changeSelectedItem(label || ""); + }, [changeSelectedItem, label]); return (
{children}
- ) -} + ); +}; ``` ```tsx // AccordionPanel component export const AccordionPanel: React.FC<{ - children: ReactNode - label?: string - className?: string -}> = ({ children, label, className }) => { - const { activeItem } = useAccordionContext() + children: ReactNode; + __cb__internal__accordion_label?: string; + className?: string; +}> = ({ children, __cb__internal__accordion_label: label, className }) => { + const { activeItem } = useAccordionContext(); + const panelStyles = [ "accordion-panel", label === activeItem ? "show-item" : "hide-item", - className, - ].join(" ") + className + ].join(" "); - return
{children}
-} + return
{children}
; +}; ``` We have done with creating all other components. Let's see what we have done. From 083dca224ae3fbd07431111151958a017289abd2 Mon Sep 17 00:00:00 2001 From: Ashwin kumar Date: Wed, 26 May 2021 12:07:37 +0530 Subject: [PATCH 5/5] Add diagram for the accordion and made some changes --- .../2021-5-25-React-compound-compnents.md | 62 ++++++++++-------- .../images/accordion-diagram.png | Bin 0 -> 30161 bytes 2 files changed, 33 insertions(+), 29 deletions(-) create mode 100644 posts/react-compound-components/images/accordion-diagram.png diff --git a/posts/react-compound-components/2021-5-25-React-compound-compnents.md b/posts/react-compound-components/2021-5-25-React-compound-compnents.md index 3f5609f..4c80438 100644 --- a/posts/react-compound-components/2021-5-25-React-compound-compnents.md +++ b/posts/react-compound-components/2021-5-25-React-compound-compnents.md @@ -7,9 +7,11 @@ description: >- This article explains with an example what compound components in react are . How to build a compound component with a tutorial to build accordion. keywords: - reactjs - - Compound-components - - Hooks - - Typescript + - compound-components + - hooks + - typescript + - tutorial + - react context link: /how-to-build-react-compound-components-tutorial category: - Tutorial @@ -45,12 +47,14 @@ In the above example, when you click on an option in the select component, selec we will build an Accordion component using the compound component pattern. +![accordion-diagram](./images/accordion-diagram.png) + The accordion component will have four components. -1. **Accordion** - The outer wrapper component of the Accordion component. This is the root component of the Accordion component. -2. **AccordionItem** - The component that allows us to define each accordion item. Each AccordionItem will have its AccordionButton and AccordionPanel components. -3. **AccordionButton** - The header for the Accordion component.On clicking the accordion button will open the corresponding accordion panel. -4. **AccordionPanel** - The panel for the accordion. This will hold the content of each accordion item. +1. **Accordion (violet)** - The outer wrapper component of the Accordion component. This is the root component of the Accordion component. +2. **AccordionItem (blue)** - The component that allows us to define each accordion item. Each AccordionItem will have its AccordionButton and AccordionPanel components. +3. **AccordionButton (green)** - The header for the Accordion component.On clicking the accordion button will open the corresponding accordion panel. +4. **AccordionPanel (red)** - The panel for the accordion. This will hold the content of each accordion item. We are going to create the above mentioned components one by one and also let's see how we can create the link between them. Let's start with Accordion component. Accordion component will wrap the other components. It will also maintain shared state with other components. In this case the selected accordion item (active item) @@ -137,15 +141,15 @@ export const AccordionItem: React.FC<{ // label is used to distinguish between each accordion element. // Adding the label prop to the children of accordionItem along with other props. - const accordionItemChildren = childrenArray.map((child) => { + const accordionItemChildren = childrenArray.map(child => { if (React.isValidElement(child)) { return React.cloneElement(child, { ...child.props, - __cb__internal__accordion_label: label - }); + __cb__internal__accordion_label: label, + }) } - return null; - }); + return null + }) return
{accordionItemChildren}
} ``` @@ -153,14 +157,14 @@ export const AccordionItem: React.FC<{ ```tsx // AccordionButton component export const AccordionButton: React.FC<{ - children: ReactNode; - __cb__internal__accordion_label?: string; - className?: string; + children: ReactNode + __cb__internal__accordion_label?: string + className?: string }> = ({ __cb__internal__accordion_label: label, children, className }) => { - const { changeSelectedItem } = useAccordionContext(); + const { changeSelectedItem } = useAccordionContext() const accordionButtonClickHandler = useCallback(() => { - changeSelectedItem(label || ""); - }, [changeSelectedItem, label]); + changeSelectedItem(label || "") + }, [changeSelectedItem, label]) return (
{children}
- ); -}; + ) +} ``` ```tsx // AccordionPanel component export const AccordionPanel: React.FC<{ - children: ReactNode; - __cb__internal__accordion_label?: string; - className?: string; + children: ReactNode + __cb__internal__accordion_label?: string + className?: string }> = ({ children, __cb__internal__accordion_label: label, className }) => { - const { activeItem } = useAccordionContext(); + const { activeItem } = useAccordionContext() const panelStyles = [ "accordion-panel", label === activeItem ? "show-item" : "hide-item", - className - ].join(" "); + className, + ].join(" ") - return
{children}
; -}; + return
{children}
+} ``` We have done with creating all other components. Let's see what we have done. -- In the Accordion-item, label prop is used to differentiate between different accordion items. The label prop will be required in the accordionButton and accordionPanel components, so we are adding label prop to the accordionItem children along with the other props. +- In the Accordion-item, label prop is used to differentiate between different accordion items. The label prop will be required in the accordionButton and accordionPanel components, so we are passing an internal label prop to the children of accordion-item along with the other props. - We are using the **useAccordionContext** in the AccordionPanel and AccordionButton. That is how we get the data that is being provided from the Accordion component. - We use changeSelectedItem in the AccordionButton component to update the active item when the button is clicked. - We use activeItem in the AccordionPanel component whether show the content or hide the content diff --git a/posts/react-compound-components/images/accordion-diagram.png b/posts/react-compound-components/images/accordion-diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..80787bd813801280f0f39e68536f93b51e4a4aec GIT binary patch literal 30161 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