{"id":45808719,"url":"https://github.com/ArtemZhyto/Modal-layout-component","last_synced_at":"2026-03-01T17:01:10.290Z","repository":{"id":331351516,"uuid":"1126292686","full_name":"ArtemZhyto/Modal-layout-component","owner":"ArtemZhyto","description":"Accessible React/Next.js modal component with focus trap, keyboard navigation, and scroll lock.","archived":false,"fork":false,"pushed_at":"2026-01-04T14:17:12.000Z","size":29,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-13T23:59:32.696Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ArtemZhyto.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-01T15:38:28.000Z","updated_at":"2026-01-04T14:16:29.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ArtemZhyto/Modal-layout-component","commit_stats":null,"previous_names":["artemzhyto/modal-layout-component"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/ArtemZhyto/Modal-layout-component","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArtemZhyto%2FModal-layout-component","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArtemZhyto%2FModal-layout-component/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArtemZhyto%2FModal-layout-component/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArtemZhyto%2FModal-layout-component/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ArtemZhyto","download_url":"https://codeload.github.com/ArtemZhyto/Modal-layout-component/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArtemZhyto%2FModal-layout-component/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29976272,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-01T16:35:47.903Z","status":"ssl_error","status_checked_at":"2026-03-01T16:35:44.899Z","response_time":124,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5: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":[],"created_at":"2026-02-26T15:00:45.901Z","updated_at":"2026-03-01T17:01:10.282Z","avatar_url":"https://github.com/ArtemZhyto.png","language":"TypeScript","readme":"# Modal-layout-component\n\nA small, accessible headless modal layout component for React / Next.js (TypeScript).\nThis repository contains a focus-trapping, keyboard-friendly modal with body scroll locking and CSS-driven open/close animations. The component is lightweight and designed to be used in Next.js \"use client\" components, but it works in any React environment that supports hooks and TypeScript.\n\nTable of contents\n-----------------\n- [Overview](#overview)\n- [Features](#features)\n- [Usage example](#usage-example)\n- [Props](#props)\n- [Styling](#styling)\n- [Accessibility](#accessibility)\n- [Development](#development)\n- [Contributing](#contributing)\n- [Supporting the project](#supporting-the-project)\n- [License](#license)\n\nOverview\n--------\n`Modal-layout-component` provides a modal wrapper that:\n- traps focus inside the modal,\n- handles keyboard controls (Tab, Shift+Tab, Escape),\n- prevents body scrolling while open,\n- supports a CSS animation for closing,\n- clones child components to inject a `closeModal` function prop for convenience.\n\nIt was written in TypeScript and intended for easy drop-in use in Next.js projects (client components).\n\nFeatures\n--------\n- Focus trapping within modal content\n- Escape key to close\n- Tab / Shift+Tab cycling of focusable elements\n- Body scroll locking while modal is open (preserves scroll position)\n- Prevents scroll via touchmove for mobile\n- CSS-driven close animation (class `modal--closing`)\n- Child components receive `closeModal` prop (if they are valid React elements)\n\nUsage example\n-----\n\n```tsx\nimport { useState } from \"react\"\nimport Modal from \"@components-modals/Modal\" // adjust path if needed\n\nconst Parent = () =\u003e {\n  const [open, setOpen] = useState(false)\n\n  return (\n    \u003c\u003e\n      \u003cbutton onClick={() =\u003e setOpen(true)}\u003eOpen modal\u003c/button\u003e\n\n      {open \u0026\u0026 (\n        \u003cModal onClose={() =\u003e setOpen(false)}\u003e\n          \u003cdiv\u003e\n            \u003ch2\u003eModal Title\u003c/h2\u003e\n            \u003cp\u003eModal content\u003c/p\u003e\n            \u003cbutton onClick={() =\u003e setOpen(false)}\u003eClose\u003c/button\u003e\n          \u003c/div\u003e\n        \u003c/Modal\u003e\n      )}\n    \u003c/\u003e\n  )\n}\n```\n\nChild components that need to trigger closing can accept a `closeModal` prop. The modal will clone children that are valid React elements and pass `closeModal` automatically.\n\nProps\n-----------\nModal component (TypeScript):\n\n- Props\n  - children: React.ReactNode\n  - onClose: () =\u003e void — called when the modal finishes closing (after close animation ends).\n\nInjected child prop:\n- closeModal: () =\u003e void — injected into any valid React element child (or array of children) so children can close the modal programmatically.\n\nStyling\n-------\nMinimum CSS expectations (class names used in the component):\n- `.modal-backdrop` — backdrop container\n- `.modal-backdrop.modal--open` — open state (used to trigger opening animation)\n- `.modal-backdrop.modal--closing` — closing state (used to trigger closing animation). The component listens for `animationend` to call `onClose`.\n- `.modal-content` — content container inside backdrop (this element receives focus and is used for focus trapping)\n\nImplement open/close animations in CSS and ensure the backdrop fires an `animationend` event so the component finishes closing before `onClose` is called.\n\nAccessibility\n-------------\n- Focus is moved into the modal on open (the `.modal-content` receives initial focus).\n- Focus is trapped inside the modal. Tabbing cycles through focusable elements.\n- Escape key closes the modal.\n- Arrow keys / PageUp / PageDown / Home / End / Space are prevented while the active element is not a text input or contentEditable to avoid page scrolling while modal is open.\n- Body scroll is locked by applying `position: fixed` and preserving previous scroll position (restored on close).\n- The backdrop listens for click to close; clicks inside `.modal-content` stop propagation so clicks inside the modal do not close it.\n\nDevelopment\n-----------\nRun locally (typical Next.js project):\n\n1. Place component files into your project, for example:\n- components-modals/Modal.tsx\n\nAlso create:\n- styles-modals/Modal.scss\n\n2. Start dev server:\n```bash\nnpm run dev\n# or\nyarn dev\n```\n\n3. Test keyboard navigation, focus trapping, and the close animation.\n\nContributing\n------------\nContributions are welcome. Please open issues for bugs or feature requests and submit pull requests with clear descriptions and tests where appropriate.\n\nSuggested CONTRIBUTING steps:\n- Fork the repo\n- Create a feature branch\n- Open a pull request with a descriptive title and description of changes\n\nSupporting the project\n------------\nIf this tool helps you in your work or studies, consider supporting development:\n\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://send.monobank.ua/jar/8HQAch1y6E\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/🚀_Support_Development-Monobank-%2300B2FF?style=for-the-badge\u0026logo=monobank\" alt=\"Support Development\" height=\"50\" style=\"border-radius: 8px;\"\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\nYour support helps improve and maintain all projects!\n\nLicense\n-------\nThis repository is licensed under the Apache License 2.0. See the [LICENSE](./LICENSE) file for details.\n","funding_links":[],"categories":["Extensions"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FArtemZhyto%2FModal-layout-component","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FArtemZhyto%2FModal-layout-component","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FArtemZhyto%2FModal-layout-component/lists"}