🚧 VeloxKit is pre-release software. APIs may change before v1.0. Get started →
Documentation
Components
Popover

Popover Stable WINMACLNX

VeloxKit provides a root-level floating overlay layer that renders content above all other elements — never clipped by ScrollView or any other ancestor. Select and DatePicker use this layer internally. You can open your own popovers with openPopover / closePopover.

How it works

render() automatically injects a PopoverHost component alongside your app root. You never mount it manually — it is always available.

API

import { openPopover, closePopover } from 'veloxkit'
 
const id = openPopover(options)
closePopover(id)

openPopover(options)

OptionTypeDescription
xnumberLeft edge of the anchor element (from __velox_getLayout)
ynumberTop edge of the anchor element
hnumberHeight of the anchor element (popover opens below it)
widthnumberWidth of the popover
contentHnumberExpected height of the popover content (used for flip calculation)
render() => ReactElementContent to render inside the popover
onClose() => voidCalled when the user clicks outside

Returns a numeric id. Pass it to closePopover(id) to dismiss programmatically.

The popover:

  • Opens below the anchor by default
  • Flips above the anchor when it would extend past the window bottom
  • Clamps horizontally so it stays on screen
  • Closes when the user clicks anywhere outside it

Example — custom tooltip

import { useRef, useCallback } from 'react'
import { openPopover, closePopover } from 'veloxkit'
 
function InfoButton({ tip }) {
  const containerRef = useRef(null)
  const popoverIdRef = useRef(null)
 
  const onMount = useCallback((id) => { containerRef.current = id }, [])
 
  const show = () => {
    const l = __velox_getLayout(containerRef.current)
    if (!l) return
    popoverIdRef.current = openPopover({
      x: l.x, y: l.y, h: l.height,
      width: 220, contentH: 60,
      onClose: () => { popoverIdRef.current = null },
      render: () => (
        <View style={{ padding: 12, backgroundColor: '#1e2235', borderRadius: 8,
                       borderWidth: 1, borderColor: '#3c4464' }}>
          <Text style={{ color: '#cdd6f4', fontSize: 13 }}>{tip}</Text>
        </View>
      ),
    })
  }
 
  const hide = () => {
    if (popoverIdRef.current != null) {
      closePopover(popoverIdRef.current)
      popoverIdRef.current = null
    }
  }
 
  return (
    <Pressable _veloxOnMount={onMount} onPress={show} onBlur={hide}
               style={{ width: 20, height: 20, alignItems: 'center', justifyContent: 'center' }}>
      <Text style={{ color: '#7aa2f7', fontSize: 13 }}>?</Text>
    </Pressable>
  )
}

Example — custom dropdown menu

function MoreMenu({ actions }) {
  const containerRef = useRef(null)
  const popoverIdRef = useRef(null)
  const onMount = useCallback((id) => { containerRef.current = id }, [])
 
  const open = () => {
    const l = __velox_getLayout(containerRef.current)
    if (!l) return
    popoverIdRef.current = openPopover({
      x: l.x, y: l.y, h: l.height,
      width: 180, contentH: actions.length * 40,
      onClose: () => { popoverIdRef.current = null },
      render: () => (
        <View style={{ backgroundColor: '#1e2235', borderRadius: 8,
                       borderWidth: 1, borderColor: '#3c4464', overflow: 'hidden' }}>
          {actions.map((action, i) => (
            <Pressable key={i} onPress={() => { action.fn(); closePopover(popoverIdRef.current) }}
                       style={({ hovered }) => ({
                         height: 40, paddingHorizontal: 14,
                         alignItems: 'center', justifyContent: 'flex-start', flexDirection: 'row',
                         backgroundColor: hovered ? '#2a3048' : 'transparent',
                       })}>
              <Text style={{ color: action.destructive ? '#f38ba8' : '#cdd6f4', fontSize: 14 }}>
                {action.label}
              </Text>
            </Pressable>
          ))}
        </View>
      ),
    })
  }
 
  return (
    <Pressable _veloxOnMount={onMount} onPress={open}
               style={{ width: 32, height: 32, alignItems: 'center', justifyContent: 'center' }}>
      <Text style={{ color: '#7aa2f7', fontSize: 18 }}>⋯</Text>
    </Pressable>
  )
}

__velox_getLayout(nodeId) returns { x, y, width, height } in screen coordinates. The nodeId is the value passed to a _veloxOnMount callback.