New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

@slithy/modal-kit

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@slithy/modal-kit

Headless modal React components for @slithy/modal-core.

latest
npmnpm
Version
0.1.4
Version published
Maintainers
1
Created
Source

@slithy/modal-kit

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.

Installation

pnpm add @slithy/modal-core @slithy/modal-kit

Minimal Setup (no animation)

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

Primitives

These are the building blocks. Each can be composed directly or wrapped by animation adapters.

ModalContainer

Fixed-position layout shell. Handles horizontal alignment and scroll behavior.

<ModalContainer alignX="center" scrollable modalId={id}>
  {/* ModalContent, etc. */}
</ModalContainer>
PropTypeDefault
alignX'center' | 'left' | 'right''center'
scrollableboolean
modalIdstring
onBackdropClick() => void
classNamestring

ModalContent

Content wrapper. Controls vertical alignment, pointer events during close, and the data-disable-opacity toggle.

<ModalContent alignY="middle" modalState={modalState} disableOpacityTransition>
  {/* ModalDialog, etc. */}
</ModalContent>
PropTypeDefault
alignY'middle' | 'top' | 'bottom'
modalStateModalState
disableOpacityTransitionboolean
styleCSSProperties

ModalDialog

The <dialog open> element with correct ARIA attributes, focus target, and modal-dialog styles.

<ModalDialog
  ref={contentRef}
  aria-label="My Modal"
  onKeyDown={onKeyDown}
>
  {children}
</ModalDialog>
PropType
aria-labelstring
classNamestring
onKeyDown(e: KeyboardEvent<HTMLDialogElement>) => void
styleCSSProperties

ModalBackdrop

Fixed-position backdrop with click handling via usePointerClick.

<ModalBackdrop onClick={handleClose} />
PropType
onClick() => void
classNamestring
styleCSSProperties

Components

Modal

Reference 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>

ModalRenderer

Renders 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>}
/>
PropTypeDescription
renderBackdrop() => ReactNodeBackdrop; caller controls visibility and animation
renderLayer(children) => ReactNodeWrap all modals in a layer context
renderPortal(children) => ReactNodeWrap each modal in a portal

Hooks

useModalLogic

The 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
})

useDialogKeyDown

Composes the Escape-key close handler and useTrapFocus into a single onKeyDown for a <dialog>.

const onKeyDown = useDialogKeyDown({
  dismissible,
  handleCloseModal,
  isTopModal,
  layerIsActive,
  onKeyDown: trapFocus.onKeyDown,
})

Building an Adapter

An adapter:

  • Calls useModalLogic (with delayAtRest: true if it animates)
  • Wraps ModalContent, ModalDialog, etc. with its animation library (e.g. animated(ModalDialog))
  • Calls markAtRest() when the enter animation completes
  • Passes onLeave to play the leave animation before calling done()
  • Wraps ModalRenderer with renderBackdrop to inject an animated backdrop

See @slithy/modal-spring for a complete example.

Exports

ExportDescription
ModalReference non-animated modal component
ModalBackdropFixed-position backdrop primitive
ModalContainerLayout shell primitive
ModalContentContent wrapper primitive
ModalDialog<dialog> element primitive
ModalRendererRenders all open modals from the store
useDialogKeyDownEscape + trapFocus key handler hook
useModalLogicCore lifecycle and behavior hook
ModalBackdropProps
ModalContentProps
ModalDialogProps
ModalProps
ModalRendererProps
UseModalLogicOptions
UseModalLogicResult

FAQs

Package last updated on 03 Apr 2026

Did you know?

Socket

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.

Install

Related posts