# WPopover
A flexible popover component for creating dropdown menus, notification panels, user menus, tooltips, and similar overlay patterns.
- [Basic Usage](#basic-usage)
- [Constructor](#constructor)
- [Props](#props)
- [Layout Modes](#layout-modes)
- [Event Handling](#event-handling)
- [State Variants](#state-variants)
- [Styling Examples](#styling-examples)
- [All Supported Classes](#all-supported-classes)
- [Customizing Theme](#customizing-theme)
- [Related Documentation](#related-documentation)
```dart
WPopover(
alignment: PopoverAlignment.bottomRight,
className: 'w-64 bg-white dark:bg-gray-800 rounded-xl shadow-xl p-2',
triggerBuilder: (context, isOpen, isHovering) => WButton(
className: 'bg-blue-600 text-white',
child: Text('Open Menu'),
),
contentBuilder: (context, close) => Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(title: Text('Profile'), onTap: close),
ListTile(title: Text('Settings'), onTap: close),
],
),
)
```
## Basic Usage
The `WPopover` widget uses two builders: `triggerBuilder` for the element that activates the popover, and `contentBuilder` for the overlay content. It manages the overlay state and positioning automatically.
```dart
WPopover(
triggerBuilder: (context, isOpen, isHovering) => WText(
'Click me',
className: 'text-blue-500 cursor-pointer',
),
contentBuilder: (context, close) => WDiv(
className: 'p-4',
child: WText('Hello from Popover!'),
),
)
```
## Constructor
```dart
const WPopover({
Key? key,
required PopoverTriggerBuilder triggerBuilder,
required PopoverContentBuilder contentBuilder,
PopoverController? controller,
bool enableTriggerOnTap = true,
PopoverAlignment alignment = PopoverAlignment.bottomLeft,
String? className,
Offset offset = const Offset(0, 4),
double maxHeight = 400,
bool disabled = false,
bool closeOnContentTap = false,
VoidCallback? onOpen,
VoidCallback? onClose,
})
```
## Props
| Prop | Type | Default | Description |
|:-----|:-----|:--------|:------------|
| `triggerBuilder` | `PopoverTriggerBuilder` | **Required** | Builder for the trigger widget. Receives `isOpen` and `isHovering` states. |
| `contentBuilder` | `PopoverContentBuilder` | **Required** | Builder for the popover content. Receives a `close` callback. |
| `className` | `String?` | `null` | Wind utility classes for the popover container styling. |
| `controller` | `PopoverController?` | `null` | Optional controller for programmatic show/hide/toggle. |
| `alignment` | `PopoverAlignment` | `bottomLeft` | Where to position the popover relative to the trigger. |
| `offset` | `Offset` | `Offset(0, 4)` | Gap between the trigger and the popover. |
| `maxHeight` | `double` | `400` | Maximum height for the content. It will scroll if exceeded. |
| `enableTriggerOnTap` | `bool` | `true` | Whether tapping the trigger toggles the popover. |
| `closeOnContentTap` | `bool` | `false` | Whether tapping inside the content closes the popover. |
| `disabled` | `bool` | `false` | When true, the trigger will not respond to interactions. |
| `onOpen` | `VoidCallback?` | `null` | Callback fired when the popover is opened. |
| `onClose` | `VoidCallback?` | `null` | Callback fired when the popover is closed. |
| `autoFlip` | `bool` | `true` | When true, the popover flips its alignment to the opposite side if the natural position would render off-screen. |
## Layout Modes
While `WPopover` itself isn't a layout container, it supports various **Alignment Modes** to determine how the overlay is positioned relative to the trigger.
### Alignment
`WPopover` intelligently "flips" the alignment if the requested position would cause the overlay to overflow the screen edges.
| Alignment | Description |
|:----------|:------------|
| `bottomLeft` | Below trigger, aligned to left edge (Default). |
| `bottomRight` | Below trigger, aligned to right edge. |
| `bottomCenter` | Below trigger, centered horizontally. |
| `topLeft` | Above trigger, aligned to left edge. |
| `topRight` | Above trigger, aligned to right edge. |
| `topCenter` | Above trigger, centered horizontally. |
## Event Handling
The `triggerBuilder` provides the `isOpen` and `isHovering` states, allowing you to reactively style the trigger. The `contentBuilder` provides a `close` callback to dismiss the popover from within the content (e.g., when a menu item is clicked).
```dart
WPopover(
triggerBuilder: (context, isOpen, isHovering) => WDiv(
className: 'p-2 rounded ${isOpen ? "bg-blue-100" : "bg-gray-100"}',
child: WText(isOpen ? 'Active' : 'Idle'),
),
contentBuilder: (context, close) => WButton(
onTap: close,
child: Text('Click to Close'),
),
)
```
## State Variants
Since the popover trigger is built via `triggerBuilder`, you can apply state-based styling manually or use Wind's state prefixes if the trigger is a Wind widget like `WButton` or `WDiv`.
```dart
WPopover(
triggerBuilder: (context, isOpen, isHovering) => WButton(
// Use the isOpen boolean for manual state toggling
className: 'p-2 rounded-lg ${isOpen ? "bg-blue-600 text-white" : "bg-white text-gray-800"}',
child: Text('Toggle Menu'),
),
contentBuilder: (context, close) => MyContent(),
)
```
## Styling Examples
### Custom Size and Shadow
If no width is specified in `className`, the popover uses the trigger's width as a minimum. Use sizing utilities to define a specific width.
```dart
WPopover(
className: 'w-80 bg-white rounded-2xl shadow-2xl border border-gray-100',
triggerBuilder: (context, isOpen, isHovering) => Icon(Icons.more_horiz),
contentBuilder: (context, close) => MyLargeMenu(),
)
```
### Dark Mode
`WPopover` fully supports dark mode styling using the `dark:` prefix.
```dart
WPopover(
className: 'bg-white dark:bg-gray-900 border-gray-200 dark:border-gray-800 shadow-xl',
triggerBuilder: (context, isOpen, isHovering) => MyTrigger(),
contentBuilder: (context, close) => MyContent(),
)
```
## All Supported Classes
The popover overlay container is a `WDiv` and supports all standard Wind utilities.
| Category | Classes |
|:---------|:--------|
| Sizing | `w-{size}`, `max-w-{size}`, `h-{size}`, `max-h-{size}` |
| Background | `bg-{color}`, `bg-opacity-{n}` |
| Borders | `border`, `border-{color}`, `rounded-{size}` |
| Shadow | `shadow-{size}`, `shadow-{color}/{opacity}` |
| Padding | `p-{n}`, `px-{n}`, `py-{n}` |
## Customizing Theme
Popovers inherit from global theme scales. You can customize the default appearance by modifying the `WindThemeData`.
```dart
WindThemeData(
colors: {
'popover-bg': Colors.white,
},
baseSpacingUnit: 4.0,
)
```
## Related Documentation
- [WSelect - A high-level dropdown built using WPopover](./w-select.md)
- [WDiv - The base container widget](../widgets/w-div.md)
- [WAnchor - Useful for interactive elements inside the popover](./w-anchor.md)