BrickclayDesign System

Popover

A floating panel anchored to a trigger, with rich projected content rather than the plain text bkTooltip takes. There are 12 placements, four sides x three alignments, and the panel keeps itself on screen: it moves to the opposite side when the requested one has no room, and slides along the edge otherwise. The arrow always tracks the trigger, never the panel, so it keeps pointing at what opened it however far the panel had to move.

bk-popoverMessaging and overlaysAngular

Preview

A working preview of Popover in the Brickclay style. Try it.

Share linkAnyone with the link can view.Quick infoPopovers can hold rich content.
Interact with the preview to see events here.

Interactive playground

Requested: bottom  ·  Resolved: bottom

placement

trigger

A fixed CSS length, e.g. 320px or 50%, for when the content's natural width shouldn't drive layout. Leave empty for the default: sized to content, capped by maxWidth (280px).

Event log

Interact with the popover to see emitted events.

Examples

All 12 placements

A side (top) centres the panel on the trigger. A side plus an edge (top-left) lines that edge of the panel up with the same edge of the trigger instead. The edge names the axis the alignment runs along, so it is always concrete: above and below align horizontally (top-left, bottom-right), while left and right align vertically (left-top, right-bottom). There is no left-left.

Click

Stays open until you click outside or press Escape. Use it for anything the user has to interact with, a hover panel disappears the moment they reach for a button in it.

Hover

Opens on the way in, closes on the way out. The close is delayed and the panel cancels it, so the pointer can cross the gap and land on the content without it vanishing.

No arrow

Drop the arrow with [showArrow]="false" when the panel is wide enough that which element opened it is obvious anyway.

Disabled

[disabled]="true" stops the popover opening at all. Style the trigger itself, the popover doesn't reach into projected content.

Fixed width

[width]="'320px'" pins the panel to an exact width instead of letting the content (capped by maxWidth) decide, useful for a form or a fixed-column list that shouldn't reflow between opens as its content changes.

Driving it from outside

#ref="bkPopover" exposes open(), close(), toggle(), isOpen() and activePlacement(), so something other than the trigger can drive the panel.

API reference

Inputs <bk-popover>

NameTypeDefaultPossible valuesDescription
placementPopoverPlacement'bottom'the 12 listed belowWhere to put the panel. A preference, not a guarantee, read activePlacement() for where it landed.
triggerstring'click''click', 'hover'How the panel opens. Use click for anything interactive.
titlestring''any textOptional heading. Empty hides the header row entirely.
closablebooleanfalsetrue, falseShow the × in the header. Does nothing without a title.
disabledbooleanfalsetrue, falseStops the popover opening. Style the trigger yourself.
showArrowbooleantruetrue, falseRender the arrow. The gap stays either way.
offsetnumber8pxGap between trigger and panel. The arrow spans most of it, so going below ~8 leaves the tip overlapping the trigger.
flipbooleantruetrue, falseAllow moving to the opposite side when the requested one has no room. Sliding along the edge is not covered by this and always happens.
closeOnClickOutsidebooleantruetrue, falseClick trigger only. Off means only Escape or code can close it.
closeOnEscapebooleantruetrue, falseClose when Escape is pressed anywhere on the document.
openDelaynumber80msHover only. Stops panels firing off as the pointer sweeps past.
closeDelaynumber150msHover only. This is what makes the panel reachable, at 0 it closes while the pointer is still crossing the gap.
maxWidthstring'280px'any CSS lengthCaps the panel width. The content still decides the actual width up to this.
widthstring | nullnullany CSS length, or nullPins the panel to an exact width instead of sizing to content. Unset by default, maxWidth alone still applies in that case.
panelClassstring''any class namesExtra classes on the panel.
appendToBodybooleanfalsetrue, falseDeprecated, no-op. The panel positions via Angular CDK Overlay now, which always portals into the shared overlay container, the escape from a transformed ancestor or clipping parent this input used to opt into by hand is unconditional today. Safe to remove; kept only so existing bindings don't break.

Outputs

NamePayloadFires when
openedvoidThe panel opens, before it has been measured and positioned.
closedvoidThe panel closes, however it was closed.
openChangebooleanEither of the above. Convenient when you only track one flag.

Public members #ref="bkPopover"

MemberReturnsDescription
open()voidOpens the panel. No-op while disabled.
close()voidCloses the panel.
toggle()voidOpens or closes, whichever applies.
isOpen()Signal<boolean>Whether the panel is currently rendered.
activePlacement()Signal<PopoverPlacement>Where the panel actually is once positioned, falls back to the requested placement while closed.

Content slots

SlotDescription
[bkPopoverTrigger]The element the panel anchors to. A bare attribute on whatever you want to be the trigger, a bk-button, an icon, a span.
defaultEverything else becomes the panel's body.

PopoverPlacement

SideCentredAligned to first edgeAligned to last edgeAlignment runs along
Abovetoptop-lefttop-rightx, left and right edges
Rightrightright-topright-bottomy, top and bottom edges
Belowbottombottom-leftbottom-rightx, left and right edges
Leftleftleft-topleft-bottomy, top and bottom edges

Notes

  • Flip vs. shift. Two different rules keep the panel on screen. Flip moves it to the opposite side, and only when it actually fits there, flipping into a second bad fit just trades one clipped edge for another. Shift slides it along the edge it's on, and is not optional. Only flip changes activePlacement().
  • The arrow follows the trigger, not the panel. Its offset is measured from the trigger's centre, so a panel that shifted 60px to stay on screen still has an arrow pointing at what opened it. It stops short of the rounded corners, where it would grow out of the curve rather than a flat edge.
  • One at a time. Opening a popover closes any other one that's open. Two at once is nearly always a missed close rather than an intent.
  • Choose the trigger by content, not by weight. Anything the user must click, type into, or read at their own pace needs trigger="click". Hover panels are for glanceable detail.