CloseButton
A utility button pre-wired to close the nearest enclosing Dialog, Popover, or Disclosure — saves boilerplate for dismiss actions.
Inside a Dialog
Drop <BitBhCloseButton> anywhere inside a Dialog and it will
automatically call the dialog's close callback. No need to wire up
@onclick or pass state around.
<BitBhButton OnClick="() => isOpen = true" class="btn btn-primary">
Open dialog
</BitBhButton>
<BitBhDialog Open="isOpen" OnClose="() => isOpen = false">
<BitBhDialogBackdrop class="dialog-backdrop" />
<BitBhDialogPanel class="dialog-panel">
<BitBhDialogTitle>Deactivate account</BitBhDialogTitle>
<BitBhDialogDescription>
This will permanently deactivate your account.
</BitBhDialogDescription>
<div class="dialog-actions">
<!-- No @onclick needed — BitBhCloseButton finds the Dialog automatically -->
<BitBhCloseButton class="btn">Cancel</BitBhCloseButton>
<BitBhCloseButton class="btn btn-danger">Deactivate</BitBhCloseButton>
</div>
</BitBhDialogPanel>
</BitBhDialog>
@code {
private bool isOpen;
}.dialog-backdrop { background: rgba(0, 0, 0, 0.5); }
.dialog-panel {
margin: 4rem auto;
max-width: 28rem;
background: #fff;
border-radius: 0.75rem;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
padding: 1.5rem;
display: flex;
flex-direction: column;
gap: 0.85rem;
}
.dialog-title { font-size: 1.1rem; font-weight: 600; color: #18181b; }
.dialog-description { font-size: 0.9rem; color: #71717a; }
.dialog-actions { display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 0.5rem; }
.btn-danger {
background: #dc2626;
border-color: #dc2626;
color: #fff;
}Inside a Popover
Use BitBhCloseButton inside a popover panel to close it on click.
Combine with the As parameter to render as an anchor or any
other element.
<BitBhPopover class="popover">
<BitBhPopoverButton class="popover-button">Solutions ▾</BitBhPopoverButton>
<BitBhPopoverPanel class="popover-panel">
<h3 class="popover-title">Navigation</h3>
<!-- Render as <a> elements that also close the popover on click -->
<BitBhCloseButton As="a" href="#analytics" class="popover-nav-link">
Analytics
</BitBhCloseButton>
<BitBhCloseButton As="a" href="#engagement" class="popover-nav-link">
Engagement
</BitBhCloseButton>
<hr class="popover-divider" />
<BitBhCloseButton class="popover-dismiss">Dismiss ✕</BitBhCloseButton>
</BitBhPopoverPanel>
</BitBhPopover>.popover { position: relative; display: inline-block; }
.popover-button {
display: inline-flex;
align-items: center;
gap: 0.4rem;
padding: 0.5rem 0.9rem;
border: 1px solid #d4d4d8;
border-radius: 0.5rem;
background: #fff;
font-size: 0.9rem;
cursor: pointer;
}
.popover-panel {
position: absolute;
top: calc(100% + 0.5rem);
left: 0;
z-index: 31;
min-width: 14rem;
background: #fff;
border: 1px solid #e4e4e7;
border-radius: 0.5rem;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
padding: 0.75rem;
display: flex;
flex-direction: column;
gap: 0.4rem;
}
.popover-title { font-size: 0.9rem; font-weight: 600; margin: 0; }
.popover-nav-link { font-size: 0.85rem; color: #2563eb; text-decoration: none; padding: 0.3rem 0; }
.popover-nav-link:hover { text-decoration: underline; }
.popover-divider { border: none; border-top: 1px solid #e4e4e7; margin: 0.25rem 0; }
.popover-dismiss {
all: unset;
display: block;
width: 100%;
font-size: 0.8rem;
font-family: inherit;
color: #71717a;
cursor: pointer;
text-align: center;
padding: 0.4rem;
border-radius: 0.35rem;
box-sizing: border-box;
}
.popover-dismiss:hover { color: #18181b; background: #f4f4f5; }
.popover-dismiss:focus-visible { outline: 2px solid #2563eb; outline-offset: 2px; }Inside a Disclosure
Works the same way inside a Disclosure. The button finds the nearest closeable ancestor and calls its close method.
Here are some details you can collapse.
<BitBhDisclosure DefaultOpen="true" class="disclosure">
<BitBhDisclosureButton class="disclosure-button">
Show details
</BitBhDisclosureButton>
<BitBhDisclosurePanel class="disclosure-panel">
<div class="disclosure-body">
<p>Here are some details you can collapse.</p>
<BitBhCloseButton class="btn btn-sm">Hide details</BitBhCloseButton>
</div>
</BitBhDisclosurePanel>
</BitBhDisclosure>.disclosure {
width: 100%;
border: 1px solid #e4e4e7;
border-radius: 0.5rem;
overflow: hidden;
background: #fff;
}
.disclosure-button {
all: unset;
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
padding: 0.875rem 1.125rem;
font-weight: 500;
cursor: pointer;
box-sizing: border-box;
}
.disclosure-button:hover { background: #f4f4f5; }
.disclosure-button[data-state="open"] { background: #f4f4f5; }
.disclosure-body {
padding: 0.875rem 1.125rem 1rem;
color: #71717a;
border-top: 1px solid #e4e4e7;
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.btn-sm { font-size: 0.8rem; padding: 0.35rem 0.7rem; }Polymorphic rendering (As)
Use the As parameter to render the close button as any HTML element.
Non-native button elements automatically receive role="button",
tabindex="0", and Enter/Space keyboard handling.
The close actions below render as different elements:
<BitBhPopover class="popover">
<BitBhPopoverButton class="popover-button">Open panel ▾</BitBhPopoverButton>
<BitBhPopoverPanel class="popover-panel">
<!-- Default: renders as <button> -->
<BitBhCloseButton class="btn btn-sm">Button (default)</BitBhCloseButton>
<!-- Renders as <a> with role="button" and keyboard handling -->
<BitBhCloseButton As="a" href="#" class="popover-nav-link">
Anchor link
</BitBhCloseButton>
<!-- Renders as <div> with role="button", tabindex, keyboard -->
<BitBhCloseButton As="div" class="close-div">
Div with role="button"
</BitBhCloseButton>
</BitBhPopoverPanel>
</BitBhPopover>.popover { position: relative; display: inline-block; }
.popover-button {
display: inline-flex;
align-items: center;
gap: 0.4rem;
padding: 0.5rem 0.9rem;
border: 1px solid #d4d4d8;
border-radius: 0.5rem;
background: #fff;
font-size: 0.9rem;
cursor: pointer;
}
.popover-panel {
position: absolute;
top: calc(100% + 0.5rem);
left: 0;
z-index: 31;
min-width: 14rem;
background: #fff;
border: 1px solid #e4e4e7;
border-radius: 0.5rem;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
padding: 0.75rem;
display: flex;
flex-direction: column;
gap: 0.4rem;
}
.popover-title { font-size: 0.9rem; font-weight: 600; margin: 0; }
.popover-nav-link { font-size: 0.85rem; color: #2563eb; text-decoration: none; padding: 0.3rem 0; }
.popover-nav-link:hover { text-decoration: underline; }
.popover-divider { border: none; border-top: 1px solid #e4e4e7; margin: 0.25rem 0; }
.popover-dismiss {
all: unset;
display: block;
width: 100%;
font-size: 0.8rem;
font-family: inherit;
color: #71717a;
cursor: pointer;
text-align: center;
padding: 0.4rem;
border-radius: 0.35rem;
box-sizing: border-box;
}
.popover-dismiss:hover { color: #18181b; background: #f4f4f5; }
.popover-dismiss:focus-visible { outline: 2px solid #2563eb; outline-offset: 2px; }
.close-variants {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin-top: 0.5rem;
}
.close-div {
padding: 0.4rem 0.7rem;
background: #f4f4f5;
border-radius: 0.4rem;
font-size: 0.85rem;
cursor: pointer;
text-align: center;
}
.close-div:hover { background: #e4e4e7; }
.close-div:focus-visible { outline: 2px solid #2563eb; outline-offset: 2px; }Disabled state
Set Disabled="true" to prevent the close action. The button
receives the native disabled attribute (or aria-disabled
for non-native elements) and a data-disabled styling hook.
The disabled close button below won't close this panel:
<BitBhPopover class="popover">
<BitBhPopoverButton class="popover-button">Panel is open ▾</BitBhPopoverButton>
<BitBhPopoverPanel class="popover-panel">
<p>The disabled close button won't close this panel:</p>
<BitBhCloseButton Disabled="true" class="btn btn-sm">
Can't close (disabled)
</BitBhCloseButton>
<BitBhCloseButton class="btn btn-sm btn-primary">
Close (enabled)
</BitBhCloseButton>
</BitBhPopoverPanel>
</BitBhPopover>.popover { position: relative; display: inline-block; }
.popover-button {
display: inline-flex;
align-items: center;
gap: 0.4rem;
padding: 0.5rem 0.9rem;
border: 1px solid #d4d4d8;
border-radius: 0.5rem;
background: #fff;
font-size: 0.9rem;
cursor: pointer;
}
.popover-panel {
position: absolute;
top: calc(100% + 0.5rem);
left: 0;
z-index: 31;
min-width: 14rem;
background: #fff;
border: 1px solid #e4e4e7;
border-radius: 0.5rem;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
padding: 0.75rem;
display: flex;
flex-direction: column;
gap: 0.4rem;
}
.popover-title { font-size: 0.9rem; font-weight: 600; margin: 0; }
.popover-nav-link { font-size: 0.85rem; color: #2563eb; text-decoration: none; padding: 0.3rem 0; }
.popover-nav-link:hover { text-decoration: underline; }
.popover-divider { border: none; border-top: 1px solid #e4e4e7; margin: 0.25rem 0; }
.popover-dismiss {
all: unset;
display: block;
width: 100%;
font-size: 0.8rem;
font-family: inherit;
color: #71717a;
cursor: pointer;
text-align: center;
padding: 0.4rem;
border-radius: 0.35rem;
box-sizing: border-box;
}
.popover-dismiss:hover { color: #18181b; background: #f4f4f5; }
.popover-dismiss:focus-visible { outline: 2px solid #2563eb; outline-offset: 2px; }
/* Style the disabled state via the data-disabled attribute */
[data-disabled] {
opacity: 0.5;
cursor: not-allowed;
}