Skip to content

Instantly share code, notes, and snippets.

@ogizanagi
Last active April 24, 2023 13:42
Show Gist options
  • Save ogizanagi/f841c8f002b522426c74709eeb8347ba to your computer and use it in GitHub Desktop.
Save ogizanagi/f841c8f002b522426c74709eeb8347ba to your computer and use it in GitHub Desktop.
React Modal with multiple slots
import React, { Children, cloneElement } from 'react';
/**
* Fonction utilitaire permettant de trouver un noeud enfant correspondant à un type donné
*/
function findSlotOfType(children, slotType) {
return Children.toArray(children).find((child) => child.type === slotType);
}
function Modal({ children }) {
const close = () => {/* … */};
// Récupération de chaque slot :
const TitleComponent = findSlotOfType(children, Title);
const ContentComponent = findSlotOfType(children, Content);
const FooterComponent = findSlotOfType(children, Footer);
// Clone de l'élement FooterComponent pour lui passer la fonction close
const FooterEl = FooterComponent ? cloneElement(FooterComponent, { close }) : undefined;
return <div className="modal">
{TitleComponent}
{ContentComponent}
{FooterEl}
</div>;
}
// Chacun de nos slots est un sous-composant React dédié,
// permettant de l'identifier par son type :
function Title({ children }) {
return <h2>{children}</h2>;
}
function Content({ children }) {
return <div className="modal-content">
{children}
</div>;
}
function Footer({ children, close }) {
return <div className="modal-footer">
{/*
Dans le cas où le contenu de <Modal.Footer> est une fonction,
nous l'invoquons en lui transmettant la fonction de fermeture de la modale
*/}
{typeof children === 'function' ? children({ close }) : children}
</div>;
}
// https://react-typescript-cheatsheet.netlify.app/docs/advanced/misc_concerns#namespaced-components
export default Object.assign(Modal, { Title, Content, Footer });
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment