Popover
Click-triggered floating panel for help text, shortcuts, profile cards, and rich content.
Overview
The Popover component is a core building block of the Byteion design system, providing a robust, accessibility-compliant interface for its specific UI capabilities.
Why this exists
Popovers are floatinging panels triggered by click that can contain richer content than tooltips or dropdowns. They are the"more info" layer of UI.
Mental model
A popover is a click-triggered floating panel. Unlike a tooltip (hover, text-only), a popover can contain forms, images, or interactive content.
When to use
When not to use
Basic example
The following example demonstrates standard usage, fully compliant with Byteion's token-first approach.
Basic
Rich profile card
import { Button, Popover } from '@byteion/react/client';
export default function PopoverDemo() {
return (
<div className="flex flex-wrap gap-3 p-6">
<Popover trigger={<Button variant="outline">Help</Button>}>
<div className="max-w-xs space-y-2 p-3">
<h4 className="font-semibold text-foreground">What is this?</h4>
<p className="text-xs text-muted-foreground">
Popovers display rich contextual content like forms or help text on click.
</p>
</div>
</Popover>
<Popover trigger={<Button>Share</Button>} side="bottom">
<form className="w-72 space-y-2 p-3">
<label className="text-xs font-medium">Email</label>
<input className="h-9 w-full rounded-md border border-border px-2 text-sm"
placeholder="user@example.com" />
<Button size="sm" className="w-full">Send invite</Button>
</form>
</Popover>
</div>
);
}
<script setup lang="ts">
import { Button, Popover } from '@byteion/vue';
</script>
<template>
<div class="flex flex-wrap gap-3 p-6">
<Popover>
<template #trigger>
<Button variant="outline">Help</Button>
</template>
<div class="max-w-xs space-y-2 p-3">
<h4 class="font-semibold text-foreground">What is this?</h4>
<p class="text-xs text-muted-foreground">
Popovers display rich contextual content like forms or help text on click.
</p>
</div>
</Popover>
<Popover side="bottom">
<template #trigger>
<Button>Share</Button>
</template>
<form class="w-72 space-y-2 p-3">
<label class="text-xs font-medium">Email</label>
<input class="h-9 w-full rounded-md border border-border px-2 text-sm"
placeholder="user@example.com" />
<Button size="sm" class="w-full">Send invite</Button>
</form>
</Popover>
</div>
</template>
Variants
Each variant communicates a different meaning. Choose based on priority, not aesthetics.
Single default variant.
Sizes
Size should match the importance and context of the component.
- md — md size.
States
This component reacts seamlessly to the following interaction and data states:
- closed — Component is collapsed or hidden.
- open — Component is expanded or visible.
- default — Resting appearance before interaction.
- hover — Pointer is over the element — visual feedback via color or shadow.
- focus — Keyboard or tab focus — shows ring indicator for accessibility.
- active — Currently selected or in use.
- disabled — Non-interactive — grayed out, cursor not-allowed.
Anatomy
Usage guidelines
- Click outside to dismiss.
- Position should avoid trigger overlap.
- Keep content focused and scannable.
Do and Don't
Do
- Dismiss on outside click.
- Position smartly.
- Keep content focused.
Don't
- Do not use for navigation.
- Do not make it too large.
- Do not use instead of a modal for critical flows.
Accessibility
Trigger has aria-expanded. Panel should have a descriptive label. Escape dismisses.
Role:dialog
Customization
Follows popover tokens for shadow, border, and z-index.
Compose with React cva()
Use the exportedcva() +cn() utilities to compose your own variant on top of the Byteion tokens.
import { cva, cn, type VariantProps } from '@byteion/react';
const myPopover = cva('base classes…', {
variants: {
accent: { soft:'border-primary-200', loud:'border-primary-500' },
},
defaultVariants: { accent:'soft' },
});
type Props = React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof myPopover>;
Compose with Vue cva()
Use the exportedcva() +cn() utilities inside standard Vue setup blocks.
<script setup lang="ts">
import { computed, useAttrs } from 'vue';
import { cva, type VariantProps } from '@byteion/vue';
interface Props { accent?:'soft' |'loud' }
const props = withDefaults(defineProps<Props>(), { accent:'soft' });
const attrs = useAttrs();
const myPopover = cva('base classes…', {
variants: { accent: { soft:'border-primary-200', loud:'border-primary-500' } },
});
const cls = computed(() => myPopover({ accent: props.accent, class: attrs.class as string | undefined }));
</script>
Runtime events
Byteion keeps framework APIs idiomatic: HTML uses DOM custom events, React uses callback props, and Vue uses emitted events / v-model updates.
HTML / JS events
bi:popover:hidebi:popover:show
React callbacks
onOpenChange(open: boolean) => void
Vue emits
update:open[v: boolean]
Remote / AJAX
This component does not implement Byteion JS remote loading. Use normal HTML form submission, framework state, or your application data layer around it.
API Reference
Requires data-bi-component="popover".
HTML Data Attributes
data-bi-popoverdata-bi-popover-toggle
React Props · PopoverProps
Extracted directly fromreact/src/components/Popover.tsx.
export interface PopoverProps {
/** The triggering element. */
trigger: ReactElement<any>;
/** Popover content. */
children: ReactNode;
side?: 'top' | 'bottom';
align?: 'start' | 'center' | 'end';
className?: string;
/** Controlled open state. */
open?: boolean;
onOpenChange?: (open: boolean) => void;
}
Vue Props · PopoverProps
Extracted directly fromvue/src/components/Popover.vue.
export interface PopoverProps {
open?: boolean;
defaultOpen?: boolean;
side?: 'top' | 'bottom';
align?: 'start' | 'center' | 'end';
}
Developer tips
side and align behavior with overflow containers.
• Click, not hover: Popover is click-triggered. Do not rely on hover to open it.
• No destructive confirmations: use Modal for delete or irreversible actions.Common mistakes
Production usage tips
- Test click open/close and outside click dismissal on every trigger.
- Test Escape close — supported via
useEscapeKeyin both React and Vue. - Test keyboard navigation — Tab into the panel, Enter/Space on inner controls.
- Test inside tables, cards, navbars, modals, and scroll containers for positioning and z-index correctness.
- Test viewport edge positioning — panels near edges should not overflow or clip.
- Test dark mode and branded themes — all tokens (
bg-popover,text-popover-foreground,shadow-popover) adapt automatically. - Keep React and Vue APIs aligned with the core schema —
side/alignprops map to CSS classes and data attributes.
Premium examples
Advanced patterns available in Byteion Pro:
Related components
Unlock Premium Patterns
Get access to copy-paste ready Pro blocks, SaaS templates, and advanced data-tables built with this component.
Explore Pro Components