{"id":17638847,"url":"https://github.com/dennib/react-use-modal","last_synced_at":"2026-04-13T09:31:44.816Z","repository":{"id":144719574,"uuid":"614539455","full_name":"dennib/react-use-modal","owner":"dennib","description":"⚛ A custom hook that provides a flexible and reusable way to manage modals in React applications.","archived":false,"fork":false,"pushed_at":"2023-03-22T22:27:38.000Z","size":161,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"develop","last_synced_at":"2026-01-24T11:19:17.887Z","etag":null,"topics":["customhook","dialog","hook","modal","npm","react","reactjs","rollup","terser","typescript"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/@dinneb/react-use-modal","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dennib.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-03-15T19:46:59.000Z","updated_at":"2023-03-20T13:49:28.000Z","dependencies_parsed_at":"2023-04-24T12:02:27.478Z","dependency_job_id":null,"html_url":"https://github.com/dennib/react-use-modal","commit_stats":null,"previous_names":["dennib/usemodal"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/dennib/react-use-modal","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dennib%2Freact-use-modal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dennib%2Freact-use-modal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dennib%2Freact-use-modal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dennib%2Freact-use-modal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dennib","download_url":"https://codeload.github.com/dennib/react-use-modal/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dennib%2Freact-use-modal/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31746294,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-13T09:16:15.125Z","status":"ssl_error","status_checked_at":"2026-04-13T09:16:05.023Z","response_time":93,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["customhook","dialog","hook","modal","npm","react","reactjs","rollup","terser","typescript"],"created_at":"2024-10-23T04:05:10.373Z","updated_at":"2026-04-13T09:31:44.787Z","avatar_url":"https://github.com/dennib.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# useModal\n\n![banner2](https://user-images.githubusercontent.com/13068594/226136792-623a7e44-d93a-4b04-b8b4-2ff7c6f40336.jpg)\n\n![npm](https://img.shields.io/npm/v/@dinneb/react-use-modal?style=flat-square)\n![npm bundle size](https://img.shields.io/bundlephobia/min/@dinneb/react-use-modal@1.0.2?color=%2326b0b2\u0026style=flat-square)\n![GitHub last commit](https://img.shields.io/github/last-commit/dennib/react-use-modal?color=%230f7f89\u0026style=flat-square)\n\nreact-use-modal is a custom hook that provides a flexible and reusable way to manage modals in React applications.\n\nUse a single line of `jsx` tag to insert your `Modal component` in page and use `useModal` configuration as props. Then go from there: update the same modal with dynamic content with functions provided by the hook.\n\nIn its basic implementation `useModal` lets you manage multiple modals in page in a reusable way without the need to write complex jsx code with as many Modal components (and relative states) as the number of different modals you want.\n\n## Highlights\n\n- Great **flexibiliy**: use a single `jsx` tag updated dynamically for all the modals in you page...\n- ...or decouple part of the logic from the hook and manage it yourself in your page/component\n- **Small** and minified **bundle size**\n- Type safe with **TypeScript**\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Basic](#basic)\n  - [Alternative](#alternative)\n    - [Partial config update](#update-current-config-partially)\n    - [Decoupled logic](#decoupled-logic)\n- [Modal Component](#modal-component-coming-soon)\n- [API](#api)\n  - [Properties and methods](#properties-and-methods)\n  - [Hook configuration / Modal props](#hook-configuration--modal-props)\n  - [Buttons](#buttons)\n- [Technologies](#technologies)\n- [Contributors](#contributors)\n\n---\n\n## Installation\n\nTo install the package, you can use npm or yarn:\n\n```bash\nnpm install @dinneb/react-use-modal --save\n```\n\nor\n\n```bash\nyarn add @dinneb/react-use-modal\n```\n\n## Usage\n\n### Basic\n\n1. **Import** the `useModal` hook\n\n```jsx\nimport { useModal } from \"@dinneb/react-use-modal\";\n```\n\n2. **Call the hook** to get modal configuration and relative helper functions: `modalConfig` and `setModalConfig`.\n\n```jsx\nconst { setModalConfig, modalConfig } = useModal();\n```\n\n3. **Spread** `modalConfig` on your Modal component (you can find an example of a custom Modal component implementation below)\n\n```jsx\nconst MyPageComponent = () =\u003e {\n  const { setModalConfig, modalConfig } = useModal();\n\n  return (\n    \u003c\u003e\n      ...Some page content here...\n      \u003cModal {...modalConfig} /\u003e\n    \u003c/\u003e\n  );\n};\n```\n\n4. Use the `setModalConfig` function wherever you want passing a **configuration object** to it.\n\n```jsx\nconst MyPageComponent = () =\u003e {\n  const { setModalConfig, modalConfig } = useModal();\n\n  const handleOpenModal = () =\u003e {\n    setModalConfig({\n      open: true,\n      title: \"I'm the first modal\",\n      children:\n        \"Content message of the modal inside a component of your choice\",\n      buttons: [\n        {\n          text: \"Confirm\",\n        },\n      ],\n    });\n  };\n\n  return (\n    \u003c\u003e\n      ...Some page content here...\n      \u003cdiv onClick={handleOpenModal} className=\"btn\"\u003e\n        Show modal\n      \u003c/div\u003e\n      \u003cModal {...modalConfig} /\u003e\n    \u003c/\u003e\n  );\n};\n```\n\n![example1](https://user-images.githubusercontent.com/13068594/226113275-1ede9847-f6e8-4e97-87d0-d353bee5f4e0.jpg)\n\n\u003e _Basic example: click on \"Show modal\" button will execute `setModalConfig` with the config we defined_.\n\n### Alternative\n\n#### **Update** current config **partially**\n\nMaybe you want to update only part of current `modalConfig`, let's say we have an open modal and we would like to change part of it's content when the user presses one of it's buttons. We can achieve this by using the functino `updateModalConfig` returned by the hook like so\n\n```jsx\nconst MyPageComponent = () =\u003e {\n  const { setModalConfig, modalConfig, updateModalConfig } = useModal();\n\n  const handleOpenModal = () =\u003e {\n    setModalConfig({\n      open: true,\n      title: \"I'm the first modal\",\n      children:\n        \"Content message of the modal inside a component of your choice\",\n      buttons: [\n        {\n          text: \"Cancel\",\n        },\n        {\n          text: \"Confirm\",\n          disableClose: true,\n          onClick: showSecondModal,\n        },\n      ],\n    });\n\n  const showSecondModal = () =\u003e {\n    updateModalConfig({\n      title: \"I'm the second modal\",\n      children:\n        \"Are you sure you want to proceed?\",\n      buttons: [\n        {\n          text: \"Yes, I am!\",\n        },\n      ],\n    });\n  }\n\n\n // ... same jsx content as seen above\n\n};\n```\n\nHere we've added a second button, the cancel button simply abort the operation closing the modal (so has no need for additional handlers, the confirm button is stopped from closing the modal, we pass it a handler which calls `updteModalConfig` from the hook and we update with it only the parts of the config that we need.\n\n![example2](https://user-images.githubusercontent.com/13068594/226114740-d2d81e7c-ca27-4b9e-a055-0eb1de71a757.jpg)\n\n\u003e _Alternative usage: here you can see `updateModalConfig` in action, passing from previous config (left) to partially modified one (right)_.\n\n#### Decoupled logic\n\nIf you have some complex, maybe verbose piece of `jsx` (eg. for `children` or `buttons`) you can decouple some props handling from the hook thus leveraging from it only part of the configuration while managing the other part manually in your page/component, let's see an example for state dependent children.\n\n```jsx\nconst initialModalConfig = {\n  title: \"I'm a complex modal!\",\n};\n\nconst MyPageComponent = () =\u003e {\n  const { modalConfig, showModal } = useModal(initialModalConfig);\n  const [isSomethingActive, setIsSomethingActive] = useState \u003c boolean \u003e false;\n\n  const currentButtons: IModalButton[] = isSomethingActive\n    ? [{ text: \"Button for active state\" }]\n    : [{ text: \"Inactive btn 1\" }, { text: \"Inactive btn 2\" }];\n\n  return (\n    \u003c\u003e\n      \u003cdiv onClick={showModal} className=\"btn\"\u003e\n        Show modal\n      \u003c/div\u003e\n\n      \u003cdiv\n        onClick={() =\u003e setIsSomethingActive((prev) =\u003e !prev)}\n        className=\"btn\"\n      \u003e\n        Toggle active state\n      \u003c/div\u003e\n\n      \u003cModal {...modalConfig} buttons={currentButtons}\u003e\n        {isSomethingActive ? (\n          \u003cdiv\u003eSome jsx here for the active state\u003c/div\u003e\n        ) : (\n          \u003cdiv\u003eSome other jsx for inactive state\u003c/div\u003e\n        )}\n      \u003c/Modal\u003e\n    \u003c/\u003e\n  );\n};\n```\n\nHere yoy can see an example of `useModal` usage with non-empty initial configuration, showing the modal through `showModal` function and more importantly the decoupled/rewritten props `children` and `buttons`. This pattern can be used for complex, verbose or state dependent content.\n\n![example3](https://user-images.githubusercontent.com/13068594/226135165-5812a194-bb99-4a2c-bc17-936604a7c2ef.jpg)\n\n\u003e _Alternative usage: config through hook inital config, modal shown with `showModal`, rewritten `buttons` and `children` Modal props_.\n\n---\n\n## Modal Component (coming soon)\n\nAt the moment we **don't provide** the `Modal component`. The hook provides config and functions, you are supposed to adjust your Modal component to them. Soon we will provide an official Modal too. In the meantime you can find below an example of how we implemented the Modal for the examples seen in this doc.\n\n```tsx\n// Modal.tsx\n\nimport { ModalProps } from \"@dinneb/react-use-modal\";\nimport styles from \"./Modal.module.css\";\n\nexport const Modal = ({\n  open,\n  title,\n  children,\n  handleClose,\n  showCloseIcon,\n  buttons,\n}: ModalProps) =\u003e {\n  return open ? (\n    \u003c\u003e\n      \u003cdiv className={styles.modalBody}\u003e\n        {showCloseIcon \u0026\u0026 (\n          \u003cdiv className={styles.close} onClick={handleClose}\u003e\u003c/div\u003e\n        )}\n        \u003cdiv className={styles.title}\u003e{title}\u003c/div\u003e\n        \u003cdiv className={styles.message}\u003e{children}\u003c/div\u003e\n\n        \u003cModalActions handleClose={handleClose} buttons={buttons} /\u003e\n      \u003c/div\u003e\n      \u003cdiv className={styles.overlay} onClick={handleClose}\u003e\u003c/div\u003e\n    \u003c/\u003e\n  ) : null;\n};\n```\n\n```tsx\n// ModalActions.tsx\n\nimport { ModalProps } from \"@dinneb/react-use-modal\";\nimport styles from \"./Modal.module.css\";\n\nexport const ModalActions = ({\n  buttons,\n  handleClose,\n}: Pick\u003cModalProps, \"buttons\" | \"handleClose\"\u003e) =\u003e (\n  \u003cdiv className={styles.actions}\u003e\n    {buttons?.map(({ text, disableClose, disabled, onClick, style }, idx) =\u003e {\n      const handleClick = () =\u003e {\n        !disabled \u0026\u0026 onClick?.();\n        if (!disableClose) handleClose();\n      };\n      return (\n        \u003cdiv\n          key={idx}\n          onClick={handleClick}\n          className={styles.btn}\n          style={style}\n        \u003e\n          {text}\n        \u003c/div\u003e\n      );\n    })}\n  \u003c/div\u003e\n);\n```\n\n\u003cdetails\u003e\n  \u003csummary\u003eSee CSS Code\u003c/summary\u003e\n\n```css\n/* Modal.module.css */\n\n.overlay {\n  position: absolute;\n  z-index: 1;\n  width: 100%;\n  height: 100vh;\n  left: 0;\n  top: 0;\n  background-color: rgba(0, 0, 0, 0.6);\n}\n\n.modalBody {\n  position: absolute;\n  min-width: 300px;\n  max-width: 500px;\n  min-height: 100px;\n  left: 50%;\n  top: 50%;\n  transform: translate(-50%, -50%);\n  background-color: white;\n  border-radius: 10px;\n  z-index: 2;\n  box-shadow: 0px 5px 20px rgba(0, 0, 0, 0.5);\n  padding: 15px;\n}\n\n.title {\n  font-weight: bold;\n  margin-top: 20px;\n  font-size: 22px;\n}\n\n.message {\n  margin: 20px;\n  font-size: 16px;\n}\n\n.close:after {\n  position: absolute;\n  right: 20px;\n  top: 10px;\n  line-height: 1em;\n  font-size: 40px;\n  display: block;\n  content: \"\\00d7\";\n  cursor: pointer;\n}\n\n.actions {\n  display: flex;\n  justify-content: center;\n  gap: 10px;\n  margin-top: 30px;\n  margin-bottom: 10px;\n}\n\n.btn {\n  padding: 8px;\n  border-radius: 6px;\n  border: 1px solid grey;\n  text-align: center;\n  min-width: 80px;\n  cursor: pointer;\n}\n```\n\n  \u003c/details\u003e\n\n---\n\n## API\n\n### Properties and methods\n\n`IUseModalReturn`\n\n| Property            | Type                                      | Default                                                                                                             | Description |\n| ------------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ----------- |\n| `modalConfig`       | `IExtendedModalConfig`                    | The current configuration of the modal (usable to as Modal props), auto inject handleClose function                 |\n| `setModalConfig`    | `Dispatch\u003cSetStateAction\u003cIModalConfig\u003e\u003e`  | Replace the entire configuration of the modal with the `IModalConfig object` provided as the argument               |\n| `updateModalConfig` | `(config: Partial\u003cIModalConfig\u003e) =\u003e void` | Updates the configuration of the modal with the properties provided in the config object (merge with current state) |\n| `toggleModal`       | `() =\u003e void`                              | Toggles the visibility of the modal                                                                                 |\n| `showModal`         | `() =\u003e void`                              | Shows the modal                                                                                                     |\n| `hideModal`         | `() =\u003e void `                             | Hides the modal                                                                                                     |\n\n### Hook configuration / Modal props\n\n`IModalConfig` / `IExtendedModalConfig`\n\nThe following properties can be passed as **configuration options** when calling the useModal hook, or as props to your modal component.\nYour modal is supposed to have (or extend) the same shape of hook configuration interface: in particular the hook implement `IModalConfig` interface while the modal is supposed to extend the already _extended_ `IExtendedModalConfig` the automatically injects also and `handleClose` function to close the modal when clicking on backdrop or non-disabled buttons.\n\n| Property         | Type             | Default     | Description                             |\n| ---------------- | ---------------- | ----------- | --------------------------------------- |\n| `open`           | `boolean`        | `false`     | Whether the modal is currently open     |\n| `title?`         | `string`         | `undefined` | The title of the modal                  |\n| `showCloseIcon?` | `boolean`        | `undefined` | Whether to show top right close icon    |\n| `children?`      | `ReactNode`      | `undefined` | The content to display within the modal |\n| `buttons?`       | `IModalButton[]` | `undefined` | Whether the modal is currently open     |\n\n### Buttons\n\n`IModalButton`\n\n| Property        | Type            | Default     | Description                                                     |\n| --------------- | --------------- | ----------- | --------------------------------------------------------------- |\n| `text`          | `string`        | ``          | The text to display on the button                               |\n| `style?`        | `CSSProperties` | `{}`        | Custom styles to apply to the button                            |\n| `onClick?`      | `() =\u003e void `   | `undefined` | A function to execute when the button is clicked                |\n| `disabled?`     | `boolean`       | `undefined` | Whether the button should be disabled                           |\n| `disableClose?` | `boolean`       | `undefined` | Whether the modal should be kept open after clicking the button |\n\n---\n\n## Technologies\n\nThis is project is built with 💙 on top of:\n\n- [React.js](https://react.dev/): _The library for web and native user interfaces_\n\n- [Rollup](https://rollupjs.org/): _The JavaScript module bundler_\n\n- [Terser](https://terser.org/): _JavaScript mangler and compressor toolkit for ES6+_\n\n- [Babel](https://babeljs.io/): _A JavaScript compiler_\n\n- [Typescript](https://www.typescriptlang.org/): _A strongly typed programming language that builds on JavaScript_\n\n## Contributors\n\nAlthough I am committing the code of this project, life is always a team effort. Here you can find a list of people who contributed to this repo.\n\n- [dennib](https://github.com/dennib)\n- [PierluigiBarocci](https://github.com/PierluigiBarocci)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdennib%2Freact-use-modal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdennib%2Freact-use-modal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdennib%2Freact-use-modal/lists"}