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)
| Option | Type | Description |
|---|---|---|
x | number | Left edge of the anchor element (from __velox_getLayout) |
y | number | Top edge of the anchor element |
h | number | Height of the anchor element (popover opens below it) |
width | number | Width of the popover |
contentH | number | Expected height of the popover content (used for flip calculation) |
render | () => ReactElement | Content to render inside the popover |
onClose | () => void | Called 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.