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.
Modal
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)
}