Skip to main content

Portal Types

@codeleap/portals provides different types of portals for common UI patterns. Each type extends the base Portal class with specific configurations and behaviors.

Centered overlay dialogs for important messages or confirmations.

Creating a Modal

import { modal } from '@codeleap/portals'

const MyModal = modal()
.content((props) => {
const { toggle } = props
return (
<div>
<h2>Modal Title</h2>
<p>Modal content goes here</p>
<button onClick={toggle}>Close</button>
</div>
)
})

MyModal.open()

With ID

const UserModal = modal({ id: 'USER_MODAL' })
.content(() => <div>User modal</div>)

// Access from anywhere
import { Modal } from '@codeleap/portals'
const instance = Modal.registry.getInstance('USER_MODAL')
instance.open()

Configuration

const ConfiguredModal = modal({
id: 'CONFIGURED_MODAL',
initialParams: { theme: 'dark' },
startsOpen: false,
independent: false,
rendersWhenHidden: false,
resetParamsOnClose: true,
transitionDuration: 300,
metadata: { category: 'user-actions' }
})

Drawer

Side-sliding panels for navigation, filters, or secondary content.

Creating a Drawer

import { drawer } from '@codeleap/portals'

const SideDrawer = drawer()
.content((props) => {
const { close } = props
return (
<div>
<h2>Navigation</h2>
<nav>
<a href="/home">Home</a>
<a href="/about">About</a>
<a href="/contact">Contact</a>
</nav>
<button onClick={close}>Close</button>
</div>
)
})

SideDrawer.open()

Default Configuration

  • DEFAULT_TRANSITION_DURATION: 200ms
  • Can be customized: Drawer.DEFAULT_TRANSITION_DURATION = 250

BottomSheet

Bottom-sliding panels popular in mobile interfaces.

Creating a BottomSheet

import { bottomSheet } from '@codeleap/portals'

const FilterSheet = bottomSheet()
.content((props) => {
const { close, setParams } = props
return (
<div>
<h2>Filters</h2>
<label>
<input type="checkbox" />
Option 1
</label>
<button onClick={close}>Apply</button>
</div>
)
})

FilterSheet.open()

Default Configuration

  • DEFAULT_TRANSITION_DURATION: 200ms
  • rendersWhenHidden: true (always rendered for smooth animations)
  • resetParamsOnClose: false (preserves state between opens)

Native Methods Integration

BottomSheet can integrate with native bottom sheet libraries (like @gorhom/bottom-sheet):

import { BottomSheet } from '@codeleap/portals'

// Configure methods to call on ref
BottomSheet.openKeyMethod = 'snapToIndex'
BottomSheet.closeKeyMethod = 'close'

// Now when you call .open() or .close(), it will also call
// ref.current.snapToIndex() or ref.current.close()

Lifecycle Hooks

const MySheet = bottomSheet()
.onOpen((portal) => {
console.log('Sheet opened!', portal.ref.current)
})
.onClose((portal) => {
console.log('Sheet closed!', portal.ref.current)
})
.content(() => <div>Content</div>)

Alert

Utility class for showing typed alert modals with convenient methods.

Setup

import { Alert, modal } from '@codeleap/portals'

// Create and assign the alert modal
Alert.modal = modal({ id: 'ALERT_MODAL' })
.content((props) => {
const { title, body, type, options = [], request } = props

return (
<div className={`alert alert--${type}`}>
<h2>{title}</h2>
<p>{body}</p>
<div className="alert-buttons">
{options.map((option, index) => (
<button
key={index}
className={`button button--${option.style}`}
onClick={() => {
option.onPress?.()
request?.resolve(option)
}}
>
{option.text}
</button>
))}
</div>
</div>
)
})

Using Alerts

import { alert } from '@codeleap/portals'

// Ask
alert.ask({
title: 'Quick question',
body: 'Do you want to continue?',
options: [
{ text: 'Yes', onPress: () => console.log('Yes') },
{ text: 'No', onPress: () => console.log('No') }
]
})

// Error
alert.error({
title: 'Whoops!',
body: 'Something went wrong',
options: [{ text: 'OK' }]
})

// Warning
alert.warn({
title: 'Hang on',
body: 'Are you sure you want to delete this?',
options: [
{ text: 'Delete', style: 'destructive' },
{ text: 'Cancel', style: 'cancel' }
]
})

// Info
alert.info({
title: 'Information',
body: 'Your changes have been saved',
options: [{ text: 'Got it' }]
})

// Custom
alert.custom({
title: 'Custom Alert',
body: 'With custom type',
customData: { foo: 'bar' },
options: [{ text: 'Close' }]
})

Custom Portal Type

You can create your own portal type by extending the Portal class:

import { Portal } from '@codeleap/portals'

export class CustomPortal extends Portal {
displayName = 'CustomPortal'

static WrapperComponent = null
static DEFAULT_TRANSITION_DURATION = 300

protected get defaultTransitionDuration() {
return CustomPortal.DEFAULT_TRANSITION_DURATION
}

protected get wrapperComponent() {
return CustomPortal.WrapperComponent
}

protected getDefaultConfig() {
return {
rendersWhenHidden: true,
independent: false,
}
}
}

export function customPortal(idOrConfig) {
return new CustomPortal(idOrConfig)
}