Overview
The Popover component displays content in a floating panel that appears relative to a trigger element, ideal for dropdowns, menus, and contextual information.
Basic Usage
import PopOver from '@newtonschool/grauity';
import { useRef, useState } from 'react';
function MyComponent() {
const triggerRef = useRef(null);
const [isOpen, setIsOpen] = useState(false);
return (
<div>
<Button
ref={triggerRef}
onClick={() => setIsOpen(!isOpen)}
>
Open Popover
</Button>
<PopOver
isOpen={isOpen}
triggerRef={triggerRef}
direction="bottom"
onClose={() => setIsOpen(false)}
>
<div style={{ padding: '16px' }}>
<p>Popover content goes here</p>
</div>
</PopOver>
</div>
);
}
Controls whether the popover is visible.
triggerRef
React.RefObject<any>
required
Reference to the trigger element. Required to calculate the popover position.
Direction in which the popover should open.Available choices: top, right, bottom, left
Callback function triggered when the popover is closed.
Enable automatic position adjustment to keep popover in viewport.
shouldCloseOnOutsideClick
Close the popover when clicking outside of it.
Disable background scrolling when popover is open.
Reference to parent container. Defaults to document.body.
minimumOffset
PopOverOffset
default:"{ top: 0, left: 0, right: 0, bottom: 0 }"
Minimum margin offset from the parent container edges.Type: { top?: number, left?: number, bottom?: number, right?: number }
Width of the popover content.
Height of the popover content.
Custom position for the popover. Opens at given position without adjustments.Type: { top: number, left: number }
shouldFocusOnFirstElement
Automatically focus the first focusable element when opened.
Content to display inside the popover.
Additional CSS class name.
Direction Options
// Bottom (default)
<PopOver direction="bottom" triggerRef={triggerRef} isOpen={isOpen}>
<p>Opens below trigger</p>
</PopOver>
// Top
<PopOver direction="top" triggerRef={triggerRef} isOpen={isOpen}>
<p>Opens above trigger</p>
</PopOver>
// Left
<PopOver direction="left" triggerRef={triggerRef} isOpen={isOpen}>
<p>Opens to the left</p>
</PopOver>
// Right
<PopOver direction="right" triggerRef={triggerRef} isOpen={isOpen}>
<p>Opens to the right</p>
</PopOver>
function MenuPopover() {
const triggerRef = useRef(null);
const [isOpen, setIsOpen] = useState(false);
return (
<div>
<Button ref={triggerRef} onClick={() => setIsOpen(!isOpen)}>
Menu
</Button>
<PopOver
isOpen={isOpen}
triggerRef={triggerRef}
onClose={() => setIsOpen(false)}
width="200px"
>
<div style={{ padding: '8px 0' }}>
<Button variant="tertiary" fullWidth onClick={() => handleAction('edit')}>
Edit
</Button>
<Button variant="tertiary" fullWidth onClick={() => handleAction('duplicate')}>
Duplicate
</Button>
<Button variant="tertiary" fullWidth color="error" onClick={() => handleAction('delete')}>
Delete
</Button>
</div>
</PopOver>
</div>
);
}
With Custom Size
<PopOver
isOpen={isOpen}
triggerRef={triggerRef}
width="400px"
height="300px"
onClose={onClose}
>
<div style={{ padding: '24px' }}>
<NSTypography variant="heading-sb-h5">Custom Size</NSTypography>
<p>This popover has a custom width and height</p>
</div>
</PopOver>
Without Auto-Adjustment
<PopOver
isOpen={isOpen}
triggerRef={triggerRef}
autoAdjust={false}
onClose={onClose}
>
<p>Position won't be automatically adjusted</p>
</PopOver>
With Minimum Offset
<PopOver
isOpen={isOpen}
triggerRef={triggerRef}
minimumOffset={{ top: 20, left: 20, right: 20, bottom: 20 }}
onClose={onClose}
>
<p>Maintains 20px margin from container edges</p>
</PopOver>
Prevent Close on Outside Click
<PopOver
isOpen={isOpen}
triggerRef={triggerRef}
shouldCloseOnOutsideClick={false}
onClose={onClose}
>
<div>
<p>Click outside won't close this</p>
<Button onClick={onClose}>Close</Button>
</div>
</PopOver>
Form Popover
function FormPopover() {
const triggerRef = useRef(null);
const [isOpen, setIsOpen] = useState(false);
return (
<div>
<Button ref={triggerRef} onClick={() => setIsOpen(true)}>
Add Item
</Button>
<PopOver
isOpen={isOpen}
triggerRef={triggerRef}
onClose={() => setIsOpen(false)}
width="320px"
disableBackgroundScroll={true}
>
<div style={{ padding: '20px' }}>
<NSTypography variant="heading-sb-h6">Add New Item</NSTypography>
<input type="text" placeholder="Item name" />
<Button variant="primary" onClick={handleSubmit}>
Save
</Button>
<Button variant="tertiary" onClick={() => setIsOpen(false)}>
Cancel
</Button>
</div>
</PopOver>
</div>
);
}