# Popover & Tooltip Component Guide

> See also: `modyo://docs/widgets/components-overlay` for DModal and DOffcanvas (portal-based).

---

## DPopover

Popover component for displaying contextual content in a floating overlay. Built on Floating UI for intelligent positioning.

### Usage

```tsx
import { useState } from 'react';
import { DPopover, DButton, DCard } from '@dynamic-framework/ui-react';

// Controlled pattern
function MyComponent() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <DPopover
      open={isOpen}
      setOpen={setIsOpen}
      renderComponent={(toggle) => (
        <DButton
          text="Show Info"
          iconEnd={toggle ? 'chevron-up' : 'chevron-down'}
        />
      )}
    >
      <DCard>
        <DCard.Body>
          <h6>Popover Content</h6>
          <p>Additional information here</p>
        </DCard.Body>
      </DCard>
    </DPopover>
  );
}

// Uncontrolled pattern (simpler)
function SimplePopover() {
  return (
    <DPopover
      open={false}
      renderComponent={(toggle) => (
        <DButton text="Click me" />
      )}
    >
      <div className="p-3">
        Quick info content
      </div>
    </DPopover>
  );
}
```

### Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `open` | `boolean` | - | **Required.** Initial/controlled open state |
| `setOpen` | `(open: boolean) => void` | - | Callback for controlled state updates |
| `renderComponent` | `(open: boolean) => ReactElement` | - | **Required.** Render function for trigger element |
| `adjustContentToRender` | `boolean` | `false` | Match popover width to trigger width |
| `className` | `string` | - | Additional CSS classes |
| `style` | `CSSProperties` | - | Inline styles |
| `children` | `ReactNode` | - | Popover content |

### Control Patterns

#### Controlled Pattern (Recommended)

Use when you need external control over popover state:

```tsx
function ControlledPopover() {
  const [isOpen, setIsOpen] = useState(false);

  const handleAction = () => {
    // Perform action
    setIsOpen(false); // Close programmatically
  };

  return (
    <DPopover
      open={isOpen}
      setOpen={setIsOpen}
      renderComponent={(toggle) => (
        <DButton
          text="Options"
          iconEnd={toggle ? 'chevron-up' : 'chevron-down'}
        />
      )}
    >
      <DCard>
        <DCard.Body>
          <DButton text="Action 1" onClick={handleAction} />
          <DButton text="Action 2" onClick={handleAction} />
        </DCard.Body>
      </DCard>
    </DPopover>
  );
}
```

#### Uncontrolled Pattern

Use for simple popovers that don't need external control:

```tsx
function UncontrolledPopover() {
  return (
    <DPopover
      open={false}
      renderComponent={(toggle) => (
        <DButton text="Help" iconStart="HelpCircle" />
      )}
    >
      <div className="p-3">
        <p><strong>Help Information</strong></p>
        <p>This is helpful context for the user.</p>
      </div>
    </DPopover>
  );
}
```

### renderComponent Function

The `renderComponent` prop receives the current `open` state and must return a React element:

```tsx
// Pattern 1: Button with dynamic icon
renderComponent={(toggle) => (
  <DButton
    text="More"
    iconEnd={toggle ? 'chevron-up' : 'chevron-down'}
  />
)}

// Pattern 2: Icon button
renderComponent={(toggle) => (
  <DButton
    iconStart="MoreVertical"
    variant="link"
    ariaLabel="More options"
  />
)}

// Pattern 3: Custom element
renderComponent={(toggle) => (
  <div className={`info-trigger ${toggle ? 'active' : ''}`}>
    <DIcon icon="Info" />
    <span>Info</span>
  </div>
)}

// Pattern 4: Badge or label
renderComponent={(toggle) => (
  <span className="badge bg-primary" style={{ cursor: 'pointer' }}>
    Details
  </span>
)}
```

### Common Use Cases

- **Info popover**: Controlled with `useState`, show account details in `DCard`, close with `setIsOpen(false)`
- **Action menu**: `MoreVertical` icon trigger, flex-column of `DButton variant="link"` items
- **Filter popover**: Button trigger with chevron toggle, `DCard` body with filter controls + Apply/Clear buttons
- **Table row actions**: Uncontrolled `open={false}` with `MoreHorizontal` icon in each row

### Advanced Features

- **`adjustContentToRender={true}`**: Makes popover width match trigger width
- **DCard styling**: Use `<DCard>` with `Header`, `Body`, `Footer` as children for structured content. Set `style={{ minWidth: '300px' }}` for consistent sizing.
- **Help icon**: Uncontrolled popover with `HelpCircle` icon trigger and `maxWidth: '250px'` content div

Both DPopover and DTooltip use Floating UI for automatic positioning, flip, shift, and click-outside dismissal. No configuration needed.

### Best Practices

**When to use**: Action menus, quick info, filter panels, dropdown-like menus.
**Don't use for**: Large forms (DModal), critical decisions (DModal), full detail views (DOffcanvas).

- Use controlled (`setOpen`) when you need to close programmatically; uncontrolled (`open={false}`) for simple displays
- Make trigger clearly clickable with dynamic chevron icon for open/closed state
- Use DCard for structured content with explicit width
- Provide ARIA labels on triggers

### Quick Reference Patterns

```tsx
// Action menu: MoreHorizontal icon → flex-column of DButton variant="link"
// Info icon: DIcon Info → small text in div with maxWidth
// Filter: Button with Filter icon + chevron → DCard with controls
// User menu: Avatar + chevron → DCard with Profile/Settings/Logout links
```

### Comparison with Other Overlay Components

| Feature | DPopover | DTooltip | DModal | DOffcanvas |
|---------|----------|----------|--------|------------|
| **Trigger** | Click | Hover/Focus | Programmatic | State-based |
| **Size** | Small-Medium | Small | Any | Large |
| **Content** | Interactive | Text only | Complex | Complex |
| **Positioning** | Floating | Floating | Centered | Edge |
| **Use Case** | Menus, filters | Help text | Decisions | Details |
| **Backdrop** | None | None | Auto | Manual |

---

## DTooltip

Tooltip component for displaying helpful text on hover, focus, or click. Built on Floating UI with automatic positioning and theming.

### Usage

```tsx
import { DTooltip, DButton } from '@dynamic-framework/ui-react';

// Basic tooltip (hover)
<DTooltip
  Component={<DButton text="Hover me" />}
>
  This is helpful information
</DTooltip>

// Tooltip with icon
<DTooltip
  Component={<DIcon icon="Info" className="text-muted" />}
>
  Additional context
</DTooltip>

// Click-triggered tooltip
<DTooltip
  Component={<DButton text="Click for info" />}
  withHover={false}
  withClick={true}
>
  Click-activated tooltip
</DTooltip>
```

### Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `Component` | `ReactNode` | - | **Required.** Element that triggers tooltip |
| `children` | `ReactNode` | - | **Required.** Tooltip content (text) |
| `withHover` | `boolean` | `true` | Show on hover |
| `withClick` | `boolean` | `false` | Show on click |
| `withFocus` | `boolean` | `false` | Show on focus |
| `open` | `boolean` | `false` | Force tooltip open (for demos/testing) |
| `placement` | `'top' \| 'right' \| 'bottom' \| 'left'` | `'top'` | Tooltip position |
| `theme` | Bootstrap color | `'dark'` | Tooltip color theme |
| `size` | `'sm' \| 'lg'` | - | Tooltip size |
| `offSet` | `number` | `6` | Distance from trigger |
| `padding` | `number` | - | Padding from viewport edge |
| `className` | `string` | - | Additional CSS classes |
| `childrenClassName` | `string` | - | CSS classes for wrapper |

### Trigger Modes

- **Hover** (default): `withHover={true}` — most common
- **Click**: `withHover={false} withClick={true}` — mobile-friendly
- **Focus**: `withFocus={true}` — keyboard navigation
- **Combined**: Set multiple to `true` for cross-device support

### Placement

`placement="top"` (default) | `"right"` | `"bottom"` | `"left"`. Floating UI auto-flips if no space.

### Theming

`theme="dark"` (default) | `"light"` | `"primary"` | `"danger"` | `"success"` | any Bootstrap color.

### Sizes

`size="sm"` | default | `size="lg"`

### Common Patterns

```tsx
// Help icon next to label
<DTooltip Component={<DIcon icon="HelpCircle" className="text-muted" />}>
  Your unique 10-digit account identifier
</DTooltip>

// Truncated text — show full text on hover
<DTooltip Component={<span className="text-truncate d-inline-block" style={{ maxWidth: '150px' }}>{text}</span>}>
  {text}
</DTooltip>

// Icon button label
<DTooltip Component={<DButton iconStart="Download" variant="link" ariaLabel="Download" />}>
  Download file
</DTooltip>

// Disabled button explanation — wrap in span for hover to work
<DTooltip Component={
  <span className="d-inline-block">
    <DButton text="Submit" disabled style={{ pointerEvents: 'none' }} />
  </span>
} theme="warning">
  Complete all required fields
</DTooltip>
```

### Integration Examples

Use tooltips with: form labels (Info icon next to label), table headers (explain abbreviations like "APR"), icon-only navigation items, status badges (explain what "Pending" means), and card action buttons (label icon-only buttons).

### Advanced Features

- **Custom offset**: `offSet={12}` (default 6) — distance from trigger
- **Viewport padding**: `padding={10}` — prevent touching viewport edges
- **Long text**: Use `size="lg"` with `placement="right"` for readability
- **Multiline**: Use `{'\n'}` between lines in children

### Best Practices

- Keep text short (1-2 sentences), supplementary only — no links or interactive elements
- Combine `withHover` + `withFocus` for best cross-device experience
- Include `ariaLabel` on icon-only triggers
- Don't nest tooltips or put forms/complex UI in them
- Don't rely solely on tooltips for critical info (mobile users may miss them)

### Common Mistakes

- **Interactive content**: Don't put links/buttons in tooltips — text only
- **Disabled elements**: Wrap in `<span className="d-inline-block">` with `style={{ pointerEvents: 'none' }}` on the disabled button
- **No trigger modes**: At least one of `withHover`/`withClick`/`withFocus` must be `true`

### DTooltip vs DPopover

**Rule of thumb**: DTooltip for simple help text (hover/focus), DPopover for interactive content (click).

Replace HTML `title` attributes with DTooltip for better styling and positioning.

---

## Related Documentation

- **Component Reference:** See `_index.md` for full Dynamic UI component list
- **Layout Patterns:** See `../reference/ui-patterns.md` for widget layout best practices
- **Common Components:** See `other.md` for additional components (DTimeline, etc.)
