BjModal

Modale React rendue via createPortal sur document.body (toujours en portail, pas de prop pour le désactiver). Fermeture : overlay, bouton croix, touche Escape ; classe bj-modal-open sur le body quand open est true.

Utilisation

import { useState } from 'react'
import { BjModal } from '@flrxnt/dsbj/react'

export default function App() {
  const [open, setOpen] = useState(false)

  return (
    <>
      <button type="button" onClick={() => setOpen(true)}>Ouvrir</button>
      <BjModal
        open={open}
        onClose={() => setOpen(false)}
        title="Titre de la modale"
      >
        <p>Contenu de la modale.</p>
      </BjModal>
    </>
  )
}

Aperçu

Titre de la modale

Contenu de la modale.

Portail et cycle de vie

Le nœud de la modale est toujours monté dans document.body. Prévoir un état open côté parent et synchroniser avec votre routeur ou votre store si besoin.

onClose — patterns TypeScript

import { useCallback, useState } from 'react'
import { BjModal } from '@flrxnt/dsbj/react'

export function ModalWithStableClose() {
  const [open, setOpen] = useState(false)
  const handleClose = useCallback(() => {
    setOpen(false)
  }, [])

  return (
    <BjModal open={open} onClose={handleClose} title="Exemple">
      <p>Fermer met à jour l’état parent.</p>
    </BjModal>
  )
}

onClose — déclencheurs (aperçu structurel)

Le clic overlay, le bouton croix (si title) et la touche Escape appellent tous onClose ; gardez une seule fonction stable (useCallback) si vous la passez à des effets.

Titre

Croix · overlay · Escape → onClose

size default

bj-modal (default)

size="default" — pas de modificateur

<BjModal open={open} onClose={() => setOpen(false)} size="default" title="Taille par défaut">
  <p>Corps</p>
</BjModal>

size sm

bj-modal--sm

size="sm"

<BjModal open={open} onClose={() => setOpen(false)} size="sm" title="Petite">
  <p>Modale étroite</p>
</BjModal>

size lg

bj-modal--lg

size="lg"

<BjModal open={open} onClose={() => setOpen(false)} size="lg" title="Large">
  <p>Modale large</p>
</BjModal>

size full

bj-modal--full

size="full"

<BjModal open={open} onClose={() => setOpen(false)} size="full" title="Plein écran">
  <p>Occupe la vue</p>
</BjModal>

Sans title (pas d’en-tête ni bouton intégré)

Pas de header : fermeture overlay / Escape uniquement.

import { useState } from 'react'
import { BjModal } from '@flrxnt/dsbj/react'

export function ModalSansTitre() {
  const [open, setOpen] = useState(false)
  return (
    <BjModal open={open} onClose={() => setOpen(false)}>
      <p>Pas de barre de titre : fermer via overlay ou Escape.</p>
    </BjModal>
  )
}

Confirmer

Contenu principal.

import { useState } from 'react'
import { BjModal } from '@flrxnt/dsbj/react'

export function ModalAvecFooter() {
  const [open, setOpen] = useState(false)
  return (
    <BjModal
      open={open}
      onClose={() => setOpen(false)}
      title="Confirmer"
      footer={
        <>
          <button type="button" className="bj-btn bj-btn--secondary" onClick={() => setOpen(false)}>
            Annuler
          </button>
          <button type="button" className="bj-btn" onClick={() => setOpen(false)}>
            Valider
          </button>
        </>
      }
    >
      <p>Contenu principal.</p>
    </BjModal>
  )
}

Combinaison : title, footer, size

Réglages

className my-modal + size lg + footer

import { useState } from 'react'
import { BjModal } from '@flrxnt/dsbj/react'

export function ModalCombo() {
  const [open, setOpen] = useState(false)
  return (
    <BjModal
      open={open}
      onClose={() => setOpen(false)}
      size="lg"
      title="Réglages"
      className="my-modal"
      footer={<button type="button" className="bj-btn" onClick={() => setOpen(false)}>OK</button>}
    >
      <p>size lg + title + footer + className</p>
    </BjModal>
  )
}

Props

PropDescription
openContrôle la visibilité ; si false, le composant ne rend rien.
onCloseCallback sans argument, appelé à la fermeture (overlay, croix, Escape).
sizesm
titleTitre optionnel ; si absent, pas de header ni libellé aria-labelledby.
childrenContenu du corps (.bj-modal__body).
footerReactNode optionnel rendu dans le footer sous le corps.
classNameClasse CSS additionnelle sur la racine .bj-modal.