{"_id":"@bento/portal","_rev":"2-6c582832da42339926c23fb0cad761d4","name":"@bento/portal","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@bento/portal","version":"0.1.0","keywords":["bento","component","library","portal","primitive","react","slots"],"author":{"name":"GoDaddy Operating Company, LLC"},"license":"MIT","_id":"@bento/portal@0.1.0","maintainers":[{"name":"3rdeden","email":"npmjs@3rd-Eden.com"},{"name":"rxmarbles","email":"rmarkins@gmail.com"},{"name":"kawikabader","email":"ekbader@gmail.com"}],"homepage":"https://github.com/godaddy/bento#readme","bugs":{"url":"https://github.com/godaddy/bento/issues"},"dist":{"shasum":"b3ecc7e35f3a75997bca281e853bf11d1df582fe","tarball":"https://registry.npmjs.org/@bento/portal/-/portal-0.1.0.tgz","fileCount":11,"integrity":"sha512-Mlhvk5q4TwradJYz5z9ZEW15HqWmndMIiRs/1ZSWzkW0w6W7APbKv3CFX3mvsKLRwN4s9I5xxAu65Mon4yvvFQ==","signatures":[{"sig":"MEUCIGVITwGda2hqHHuxP0yHNruU9Fz0LPAeaomSBr+cGOakAiEA/R9rq/ayBZ+5+PuyECg9U7tkdGjGpJdaFMRyvdD0/Ls=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bento%2fportal@0.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":38757},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./package.json":"./package.json"},"gitHead":"2552a8442bd7e504706233eeb501001087058cdf","scripts":{"lint":"biome lint && tsc","test":"vitest --run","build":"tsup-node","pretest":"npm run build","posttest":"npm run lint","test:watch":"vitest","prepublishOnly":"node ../../scripts/compile-readme.ts"},"_npmUser":{"name":"kawikabader","email":"ekbader@gmail.com"},"repository":{"url":"git+https://github.com/godaddy/bento.git","type":"git"},"_npmVersion":"11.6.4","description":"Portal component primitive - render children into a target DOM container","directories":{},"_nodeVersion":"23.11.1","dependencies":{"@bento/box":"^0.2.0","@bento/slots":"^0.2.0","@bento/use-props":"^0.2.0","@react-aria/overlays":"^3.25.3","@bento/use-data-attributes":"^0.1.1"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"react":"18.x || 19.x","react-dom":"18.x || 19.x"},"_npmOperationalInternal":{"tmp":"tmp/portal_0.1.0_1764862975893_0.5934176660217865","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@bento/portal","version":"0.1.1","description":"Portal component primitive - render children into a target DOM container","type":"module","main":"./dist/index.cjs","module":"./dist/index.js","scripts":{"build":"tsup-node","lint":"biome lint && tsc","posttest":"npm run lint","prepublishOnly":"node ../../scripts/compile-readme.ts","pretest":"npm run build","test":"vitest --run","test:watch":"vitest"},"repository":{"type":"git","url":"git+https://github.com/godaddy/bento.git"},"keywords":["bento","component","library","portal","primitive","react","slots"],"author":{"name":"GoDaddy Operating Company, LLC"},"license":"MIT","bugs":{"url":"https://github.com/godaddy/bento/issues"},"homepage":"https://github.com/godaddy/bento#readme","dependencies":{"@bento/box":"^0.2.0","@bento/slots":"^0.3.0","@bento/use-data-attributes":"^0.1.1","@bento/use-props":"^0.2.1","@react-aria/overlays":"^3.25.3"},"peerDependencies":{"react":"18.x || 19.x","react-dom":"18.x || 19.x"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./package.json":"./package.json"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"gitHead":"0f8ba63cf8539136795958006c36d1aee1f70d8e","types":"./dist/index.d.ts","_id":"@bento/portal@0.1.1","_nodeVersion":"23.11.1","_npmVersion":"11.7.0","dist":{"integrity":"sha512-zlk10gnTK1gS3JTKNcuvqg4Fx20Y0MnKOmwUakKpMYWyhurAMrittNcHD6KTmlJMktfMhpPWsAHShuzymlRzug==","shasum":"3a80b68100a9d42d3595563df55ee5018051395f","tarball":"https://registry.npmjs.org/@bento/portal/-/portal-0.1.1.tgz","fileCount":11,"unpackedSize":38757,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bento%2fportal@0.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCAJ/5m8sLdcvgtgZfYpJkI76DYjwtQ8MuMmSTprVuZlwIgb/dI8OdGP6LCtLDu94j9ftu88hiaAYM0Gl3E8yUrpiE="}]},"_npmUser":{"name":"rxmarbles","email":"rmarkins@gmail.com"},"directories":{},"maintainers":[{"name":"rmarkins","email":"rmarkins@godaddy.com"},{"name":"3rdeden","email":"npmjs@3rd-Eden.com"},{"name":"rxmarbles","email":"rmarkins@gmail.com"},{"name":"kawikabader","email":"ekbader@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/portal_0.1.1_1766075454523_0.20128931116701065"},"_hasShrinkwrap":false}},"time":{"created":"2025-12-04T15:42:55.783Z","modified":"2025-12-18T16:30:55.146Z","0.1.0":"2025-12-04T15:42:56.025Z","0.1.1":"2025-12-18T16:30:54.670Z"},"bugs":{"url":"https://github.com/godaddy/bento/issues"},"author":{"name":"GoDaddy Operating Company, LLC"},"license":"MIT","homepage":"https://github.com/godaddy/bento#readme","keywords":["bento","component","library","portal","primitive","react","slots"],"repository":{"type":"git","url":"git+https://github.com/godaddy/bento.git"},"description":"Portal component primitive - render children into a target DOM container","maintainers":[{"name":"rmarkins","email":"rmarkins@godaddy.com"},{"name":"3rdeden","email":"npmjs@3rd-Eden.com"},{"name":"rxmarbles","email":"rmarkins@gmail.com"},{"name":"kawikabader","email":"ekbader@gmail.com"}],"readme":"# Portal\n\nThe `@bento/portal` package exports the **Portal** component, which renders\nchildren into a target DOM container outside the normal React component\nhierarchy. Portal solves common UI challenges like z-index conflicts, clipping\nissues, and overlay stacking by rendering content to `document.body` or a custom\ncontainer.\n\nPortal integrates seamlessly with React ARIA's `UNSAFE_PortalProvider` while\nremaining fully independent and functional without it.\n\n## Use Cases\n\nPortal is essential for UI elements that need to escape their parent container's boundaries:\n\n- **Overlays and Modals**: Prevent clipping and z-index conflicts\n- **Dropdown Menus**: Render above all other content regardless of parent constraints\n- **Tooltips**: Position freely without overflow hidden issues\n- **Toast Notifications**: Display at the application level\n- **Popovers and Dialogs**: Ensure proper stacking and positioning\n\n## Installation\n\n```bash\nnpm install --save @bento/portal\n```\n\n## Props\n\nThe `@bento/portal` package exports the `Portal` component:\n\n<Source language='tsx' code={ BasicExample } />\n\nThe following properties are available to be used on the `Portal` component:\n\n| Prop | Type | Required | Description |\n|------|------|----------|------------|\n| `container` | `Element` | No | The container to render the portal content into.\nIf not provided, Portal will check for React ARIA's PortalProvider,\nand fall back to document.body. |\n| `mounted` | `boolean` | No | Should the portal content be mounted.\nSet to false by default for server-side rendering compatibility.\nPortal will not render children if not mounted. |\n| `children` | `ReactNode \\| ((data: { props: { mounted?: boolean; }; }) => ReactNode)` | Yes | The content to render inside the portal.\nCan be a React node or a render prop function that receives props. |\n| `slot` | `string` | No | A named part of a component that can be customized. This is implemented by the consuming component.\nThe exposed slot names of a component are available in the components documentation. |\n| `slots` | `Record<string, object \\| Function>` | No | An object that contains the customizations for the slots.\nThe main way you interact with the slot system as a consumer. |\n\n## Examples\n\n### Basic\n\nBasic portal usage that renders content to `document.body`:\n\n<Source language='tsx' code={ BasicExample } />\n\n### Custom Container\n\nPortal can render to a custom container instead of `document.body`. This is\nuseful when you need to control the exact DOM location where portal content\nappears:\n\n<Source language='tsx' code={ CustomContainerExample } />\n\n## React ARIA Integration\n\nPortal optionally integrates with React ARIA's `UNSAFE_PortalProvider` to\nprovide consistent portal container management across your application. This\nexample demonstrates how Portal automatically detects and uses the\nPortalProvider's container:\n\n<Source language='tsx' code={ PortalProviderExample } />\n\n**Container priority:**\n1. Explicit `container` prop (highest priority)\n2. React ARIA's `UNSAFE_PortalProvider` container (via `useUNSAFE_PortalContext`)\n3. `document.body` (fallback)\n\n**Benefits:**\n- **Stacking context**: All overlays share the same stacking context\n- **Custom location**: Control where overlays render in DOM\n- **Multiple overlays**: Proper stacking when multiple portals/overlays are open\n- **React ARIA compatibility**: Works seamlessly with React ARIA components\n- **Graceful degradation**: Works without React ARIA installed\n\n## SSR Safety\n\nPortal is SSR-safe and will not render content on the server. The `mounted` prop\nshould be set to `true` only after the component has mounted on the client:\n\n```tsx\nfunction MyComponent() {\n  const [mounted, setMounted] = useState(false);\n\n  useEffect(() => {\n    setMounted(true);\n  }, []);\n\n  return (\n    <Portal mounted={mounted}>\n      <Container>Content</Container>\n    </Portal>\n  );\n}\n```\n\n## Accessibility\n\nPortal is designed with accessibility in mind:\n\n- **Semantic HTML**: Portal doesn't interfere with semantic HTML structure\n- **Screen Reader Support**: Content rendered through Portal remains accessible to screen readers\n- **Focus Management**: Portal doesn't trap or redirect focus - implement your own focus management as needed for modals/dialogs\n- **Keyboard Navigation**: Portal preserves keyboard navigation of its content\n- **ARIA Support**: All ARIA attributes applied to portal content are preserved\n\n**Note**: Portal is a rendering utility and doesn't provide built-in focus\n*trapping or modal behavior. For accessible modals and dialogs, combine Portal\n*with proper focus management and ARIA attributes.\n\n## Data Attributes\n\nPortal applies the following data attributes to portal content:\n\n| Attribute      | Description                        | Example Values    |\n| -------------- | ---------------------------------- | ----------------- |\n| `data-portal`  | Marks content rendered via portal  | \"true\"            |\n| `data-mounted` | Whether portal content has mounted | \"true\" / \"false\"  |\n\n## Customization\n\nPortal is a rendering utility component that doesn't render its own DOM\nelements. Instead, it renders children into a target container using React's\n`createPortal`. Because of this, Portal doesn't introduce internal slots like\nother Bento components.\n\n### Slots\n\nPortal is created using the `@bento/slots` package via `withSlots('BentoPortal',\n...)`, which means it supports the standard `slot` and `slots` props for\nintegration with parent components. However, Portal itself doesn't define any\ninternal slot assignments since it acts as a transparent rendering boundary.\n\nSee the `@bento/slots` package for more information on how to use the `slot` and\n`slots` properties.\n\n### Styling\n\nPortal applies data attributes to the children it renders, making it possible to\nstyle portal content based on its state. Since Portal doesn't render wrapper\nelements, you should apply `className` or `style` props directly to the children\nyou pass to Portal.\n\nThe data attributes Portal applies can be used in your CSS selectors:\n\n```css\n/* Target all portal content */\n[data-portal=\"true\"] {\n  /* Styles for content rendered through Portal */\n}\n\n/* Target mounted portal content */\n[data-portal=\"true\"][data-mounted=\"true\"] {\n  /* Styles for mounted portal content */\n  animation: fadeIn 200ms ease-in;\n}\n```\n\nWhen using Portal with other Bento components like `Container`, you can apply\nstyling through those components:\n\n```tsx\n<Portal mounted={mounted}>\n  <Container className=\"my-overlay\">\n    <Text>Styled portal content</Text>\n  </Container>\n</Portal>\n```\n\nThe data attributes will be applied to the Container element, allowing you to\ntarget it:\n\n```css\n.my-overlay[data-portal=\"true\"] {\n  /* Your custom styles */\n}\n```","readmeFilename":"README.md"}