useRequestModal
The useRequestModal hook returns a function to trigger a modal that is portaled outside of the view iframe. This ensures the modal is correctly displayed and not limited to the view’s area, allowing for a better user experience when displaying detailed content or forms.
Basic usage
Section titled “Basic usage”import { useRequestModal } from "@usefractal/frac/web";
function ModalTrigger() { const { open } = useRequestModal();
return ( <button onClick={() => open({ title: "Details" })}> View Details </button> );}Returns
Section titled “Returns”{ isOpen: boolean; open: (options: RequestModalOptions) => void; params?: Record<string, unknown>;}Properties
Section titled “Properties”isOpen: boolean- Whether the modal is currently openopen: (options: RequestModalOptions) => void- Function to trigger the modalparams?: Record<string, unknown>- Parameters passed when the modal was opened
RequestModalOptions
Section titled “RequestModalOptions”title?: string- The title to display in the modal headerparams?: Record<string, unknown>- Custom parameters to pass to the modalanchor?: { top?: number; left?: number; width?: number; height?: number }- Positioning anchor for the modal
Examples
Section titled “Examples”Modal with Different Content
Section titled “Modal with Different Content”import { useRequestModal } from "@usefractal/frac/web";
function ProductView() { const { open, isOpen } = useRequestModal();
// When in modal mode, show detailed view if (isOpen) { return ( <div className="product-details"> <h2>Product Details</h2> <p>Full product description with all specifications...</p> <ul> <li>Feature 1</li> <li>Feature 2</li> <li>Feature 3</li> </ul> <button>Add to Cart</button> </div> ); }
// Inline view shows summary return ( <div className="product-summary"> <h3>Product Name</h3> <p>Brief description...</p> <button onClick={() => open({ title: "Product Details" })}> View Details </button> </div> );}Settings Modal
Section titled “Settings Modal”import { useRequestModal } from "@usefractal/frac/web";import { useState } from "react";
function SettingsView() { const { open, isOpen } = useRequestModal(); const [settings, setSettings] = useState({ notifications: true, darkMode: false, language: "en", });
if (isOpen) { return ( <form className="settings-form"> <label> <input type="checkbox" checked={settings.notifications} onChange={(e) => setSettings((s) => ({ ...s, notifications: e.target.checked })) } /> Enable Notifications </label> <label> <input type="checkbox" checked={settings.darkMode} onChange={(e) => setSettings((s) => ({ ...s, darkMode: e.target.checked })) } /> Dark Mode </label> <label> Language: <select value={settings.language} onChange={(e) => setSettings((s) => ({ ...s, language: e.target.value })) } > <option value="en">English</option> <option value="fr">French</option> <option value="es">Spanish</option> </select> </label> </form> ); }
return ( <div className="settings-summary"> <span>Settings</span> <button onClick={() => open({ title: "Settings" })}> Configure </button> </div> );}Image Gallery Modal
Section titled “Image Gallery Modal”import { useRequestModal } from "@usefractal/frac/web";import { useState } from "react";
type Image = { id: string; thumbnail: string; full: string; alt: string;};
function ImageGallery({ images }: { images: Image[] }) { const { open, isOpen } = useRequestModal(); const [selectedIndex, setSelectedIndex] = useState(0);
if (isOpen) { const current = images[selectedIndex]; return ( <div className="gallery-modal"> <img src={current.full} alt={current.alt} /> <div className="gallery-nav"> <button onClick={() => setSelectedIndex((i) => Math.max(0, i - 1))} disabled={selectedIndex === 0} > Previous </button> <span> {selectedIndex + 1} / {images.length} </span> <button onClick={() => setSelectedIndex((i) => Math.min(images.length - 1, i + 1)) } disabled={selectedIndex === images.length - 1} > Next </button> </div> </div> ); }
return ( <div className="gallery-thumbnails"> {images.slice(0, 4).map((image, index) => ( <button key={image.id} onClick={() => { setSelectedIndex(index); open({ title: "Gallery" }); }} > <img src={image.thumbnail} alt={image.alt} /> </button> ))} {images.length > 4 && <span>+{images.length - 4} more</span>} </div> );}Form Modal
Section titled “Form Modal”import { useRequestModal, useViewState } from "@usefractal/frac/web";
type FormData = { name: string; email: string; submitted: boolean;};
function ContactForm() { const { open, isOpen } = useRequestModal(); const [formData, setFormData] = useViewState<FormData>({ name: "", email: "", submitted: false, });
if (isOpen) { if (formData.submitted) { return ( <div className="form-success"> <h2>Thank you, {formData.name}!</h2> <p>We'll be in touch at {formData.email}</p> </div> ); }
return ( <form className="contact-form" onSubmit={(e) => { e.preventDefault(); setFormData((prev) => ({ ...prev, submitted: true })); }} > <input type="text" placeholder="Your name" value={formData.name} onChange={(e) => setFormData((prev) => ({ ...prev, name: e.target.value })) } required /> <input type="email" placeholder="Your email" value={formData.email} onChange={(e) => setFormData((prev) => ({ ...prev, email: e.target.value })) } required /> <button type="submit">Submit</button> </form> ); }
return ( <button onClick={() => open({ title: "Contact Us" })}> Contact Us </button> );}