Components/Popover

Popover

One 320-wide floating panel with a near-black edge: a title, a description, and a slot in the middle that the component deliberately leaves empty.

Popover · Components frameLive in the browser · drawn to match the file
State
DimensionsSet the dimensions for the layer.Your content goes here
320 × 132 in the filetitle · description · content slot
A border you can actually see

The panel takes a 1px base.foreground outline, not base.border. A popover floats over content it does not own, so a hairline grey edge would let it dissolve into whatever is behind it. The near-black line is what separates it, and the shadow only lifts it.

The content slot is a placeholder

Under the title and description sits a base.muted block reading "Your content goes here". That is deliberate: the component fixes the frame, the padding and the type, and leaves the middle to you. Every panel in the usage frame replaces exactly that block.

One component, no variants

There is no size axis and no side axis. A popover is one shape whose width you set when you place it, and whose position is a runtime decision. Drawing Top, Right, Bottom and Left as variants would be four copies of the same panel.

Where it lands

Align is a runtime prop, not a variant

The source gives PopoverContent an align of start, center or end, which decides how the panel lines up against its trigger. Nothing about the panel changes - only where it is put - which is why the file draws it once.

align · start · center · endLive in the browser · drawn to match the file
Align
Aligned center The trigger has not moved. Only the panel's edge that lines up with it has.
The usage frame

Three panels, three different middles

844 by 700. The same frame, padding and type each time; what changes is the block under the description. Two labelled fields, a link beside a copy button, or a pair of buttons - and the panel width follows the content rather than the other way round.

Panel
DimensionsSet the dimensions for the layer.
Width100%
Height320px
320 × 172 in the file

Worth knowing about the file: the three panels are drawn locally rather than being instances of the Popover, because a component copy in Penpot cannot take new children - there is no way to drop two rows of fields into the content slot. The fields and buttons inside them are real Input and Button instances, so the parts are shared even where the frame is not.

In the file

One component, no variants

Read straight out of the Penpot file. The axes below are the property names you will see in the variant dropdown.

Popovernone320 × 132 - base.popover on a 1px base.foreground edge, radius.lg, two drop shadows1

Using the Popover

Because nothing about the panel changes. Size is set when you place it - the three panels in the usage frame are 320, 340 and 300 wide - and side and align are runtime props, decided by where the trigger happens to sit on screen. Drawing Top, Right, Bottom and Left as variants would be four copies of one shape.

Because a popover floats over content it does not own. A hairline grey edge lets it dissolve into whatever is behind it; the near-black line is what actually separates the two planes. The two drop shadows only lift it - they are not what defines the edge.

The content slot, and it is meant to be replaced. The component fixes the frame, the 16 of padding, the 8 gap and the type ramp, then hands you a base.muted rectangle reading "Your content goes here". Each usage panel swaps exactly that block: two labelled fields, a link beside a copy button, or a pair of buttons.

A component copy in Penpot cannot take new children, so there is no way to drop two rows of fields into the content slot of an instance. The three panels are drawn locally for that reason. Everything inside them is shared, though - the fields are Input instances and the buttons are Button instances.

Overlays · 0 variants