
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
@slithy/modal-kit
Advanced tools
The headless React layer for the @slithy modal system. Provides primitives, behavior hooks, and a renderer — everything needed to build a fully functional modal UI with no animation dependency.
modal-kit + modal-core are sufficient for a production modal system. Add @slithy/modal-spring (or a custom adapter) only if you need animated transitions.
pnpm add @slithy/modal-core @slithy/modal-kit
import { useModalStore } from '@slithy/modal-core'
import { Modal, ModalRenderer } from '@slithy/modal-kit'
// Render once at your app root
export function App() {
const { backdropId, modals } = useModalStore(({ backdropId, modals }) => ({
backdropId,
modals,
}))
const showBackdrop = !!backdropId && modals.length > 0
return (
<>
<main>{/* your app */}</main>
<ModalRenderer
renderBackdrop={() => showBackdrop ? <ModalBackdrop /> : null}
/>
</>
)
}
// Open a modal from anywhere
useModalStore.getState().openModal(
<Modal aria-label="My Modal">
<p>Content</p>
</Modal>,
{ triggerEvent: event }
)
These are the building blocks. Each can be composed directly or wrapped by animation adapters.
ModalContainerFixed-position layout shell. Handles horizontal alignment and scroll behavior.
<ModalContainer alignX="center" scrollable modalId={id}>
{/* ModalContent, etc. */}
</ModalContainer>
| Prop | Type | Default |
|---|---|---|
alignX | 'center' | 'left' | 'right' | 'center' |
scrollable | boolean | — |
modalId | string | — |
onBackdropClick | () => void | — |
className | string | — |
ModalContentContent wrapper. Controls vertical alignment, pointer events during close, and the data-disable-opacity toggle.
<ModalContent alignY="middle" modalState={modalState} disableOpacityTransition>
{/* ModalDialog, etc. */}
</ModalContent>
| Prop | Type | Default |
|---|---|---|
alignY | 'middle' | 'top' | 'bottom' | — |
modalState | ModalState | — |
disableOpacityTransition | boolean | — |
style | CSSProperties | — |
ModalDialogThe <dialog open> element with correct ARIA attributes, focus target, and modal-dialog styles.
<ModalDialog
ref={contentRef}
aria-label="My Modal"
onKeyDown={onKeyDown}
>
{children}
</ModalDialog>
| Prop | Type |
|---|---|
aria-label | string |
className | string |
onKeyDown | (e: KeyboardEvent<HTMLDialogElement>) => void |
style | CSSProperties |
ModalBackdropFixed-position backdrop with click handling via usePointerClick.
<ModalBackdrop onClick={handleClose} />
| Prop | Type |
|---|---|
onClick | () => void |
className | string |
style | CSSProperties |
ModalReference implementation. Composes all four primitives into a functional non-animated modal. Use it directly for a no-animation setup, or as a reference when building a custom adapter.
<Modal
aria-label="Settings"
alignX="center"
alignY="middle"
contentClassName="my-card"
dismissible
>
{children}
</Modal>
ModalRendererRenders all open modals from the store. Place once at the app root.
<ModalRenderer
renderBackdrop={() => showBackdrop ? <ModalBackdrop /> : null}
renderLayer={(children) => <LayerProvider>{children}</LayerProvider>}
renderPortal={(children) => <Portal>{children}</Portal>}
/>
| Prop | Type | Description |
|---|---|---|
renderBackdrop | () => ReactNode | Backdrop; caller controls visibility and animation |
renderLayer | (children) => ReactNode | Wrap all modals in a layer context |
renderPortal | (children) => ReactNode | Wrap each modal in a portal |
useModalLogicThe core modal hook. Manages registration, lifecycle, focus, and Escape key. Called by Modal and by animation adapters.
const {
contentRef, // ref to attach to <dialog>
handleCloseModal, // call to begin the close sequence
isTopModal, // whether this is the frontmost modal
layerIsActive, // whether this modal's layer is active
markAtRest, // call after enter animation completes (when delayAtRest: true)
modalId, // this modal's store ID
modalState, // 'opening' | 'open' | 'closing' | 'closed'
skipAnimation, // whether to skip animation for this instance
} = useModalLogic({
afterClose,
afterOpen,
delayAtRest, // when true, caller must call markAtRest() to unblock closing
layerIsActive, // pass from useLayerState for full layer coordination
onLeave, // (done) => void — call done() after leave animation
})
useDialogKeyDownComposes the Escape-key close handler and useTrapFocus into a single onKeyDown for a <dialog>.
const onKeyDown = useDialogKeyDown({
dismissible,
handleCloseModal,
isTopModal,
layerIsActive,
onKeyDown: trapFocus.onKeyDown,
})
An adapter:
useModalLogic (with delayAtRest: true if it animates)ModalContent, ModalDialog, etc. with its animation library (e.g. animated(ModalDialog))markAtRest() when the enter animation completesonLeave to play the leave animation before calling done()ModalRenderer with renderBackdrop to inject an animated backdropSee @slithy/modal-spring for a complete example.
| Export | Description |
|---|---|
Modal | Reference non-animated modal component |
ModalBackdrop | Fixed-position backdrop primitive |
ModalContainer | Layout shell primitive |
ModalContent | Content wrapper primitive |
ModalDialog | <dialog> element primitive |
ModalRenderer | Renders all open modals from the store |
useDialogKeyDown | Escape + trapFocus key handler hook |
useModalLogic | Core lifecycle and behavior hook |
ModalBackdropProps | — |
ModalContentProps | — |
ModalDialogProps | — |
ModalProps | — |
ModalRendererProps | — |
UseModalLogicOptions | — |
UseModalLogicResult | — |
FAQs
Headless modal React components for @slithy/modal-core.
We found that @slithy/modal-kit demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.