BlazorBlueprint.Primitives
3.5.0
dotnet add package BlazorBlueprint.Primitives --version 3.5.0
NuGet\Install-Package BlazorBlueprint.Primitives -Version 3.5.0
<PackageReference Include="BlazorBlueprint.Primitives" Version="3.5.0" />
<PackageVersion Include="BlazorBlueprint.Primitives" Version="3.5.0" />
<PackageReference Include="BlazorBlueprint.Primitives" />
paket add BlazorBlueprint.Primitives --version 3.5.0
#r "nuget: BlazorBlueprint.Primitives, 3.5.0"
#:package BlazorBlueprint.Primitives@3.5.0
#addin nuget:?package=BlazorBlueprint.Primitives&version=3.5.0
#tool nuget:?package=BlazorBlueprint.Primitives&version=3.5.0
BlazorBlueprint.Primitives
Headless, unstyled Blazor primitive components with ARIA attributes and keyboard support. Build your own component library using these composable primitives.
Features
- Headless & Unstyled: Complete control over styling — primitives provide behavior, accessibility, and state management without imposing any visual design
- Built with Accessibility in Mind: Includes ARIA attributes and keyboard interaction support
- Composition-Based: Flexible component composition patterns for building complex UIs
- Type-Safe: Full C# type safety with IntelliSense support
- State Management: Built-in controlled and uncontrolled state patterns
- Keyboard Support: Keyboard interaction support for interactive components
- Two-Layer Portal Architecture: Category-scoped portals (Container and Overlay) for efficient rendering
- .NET 8: Built for the latest .NET platform
Installation
dotnet add package BlazorBlueprint.Primitives
Setup
Register services in Program.cs:
builder.Services.AddBlazorBlueprintPrimitives();
Add the portal host to your root layout (MainLayout.razor):
<BbPortalHost />
Add a single import to _Imports.razor:
@using BlazorBlueprint.Primitives
Available Primitives
| Primitive | Description |
|---|---|
| Accordion | Collapsible content sections with single or multiple item expansion |
| Alert Dialog | Modal requiring explicit acknowledgement, no dismiss via overlay or Escape |
| Checkbox | Binary selection control with indeterminate state and BbCheckboxIndicator sub-component |
| Collapsible | Expandable content area with trigger control |
| Context Menu | Right-click menu with keyboard navigation and positioning |
| Dashboard Grid | Widget layout state, drag-and-drop coordination, resize handling, responsive breakpoints |
| DataGrid | Headless data grid with sorting, filtering, pagination, selection, expansion, row grouping, and state management |
| Dialog | Modal dialogs with backdrop, focus management, and portal rendering |
| Dropdown Menu | Context menus with items, checkbox items, separators, and keyboard shortcuts |
| Hover Card | Rich preview cards on hover with delay control |
| Label | Accessible labels for form controls with automatic association |
| Popover | Floating panels for additional content with positioning |
| Progress | Accessible progress bar with determinate and indeterminate states |
| Radio Group | Mutually exclusive options with keyboard navigation |
| Scroll Area | Custom scrollbar with accessible ARIA scrollbar role and drag support |
| Select | Dropdown selection with cascading type inference and display text resolution |
| Separator | Semantic or decorative divider with orientation support |
| Sheet | Side panels that slide in from viewport edges |
| Slider | Range input with keyboard navigation and pointer drag support |
| Switch | Toggle control with BbSwitchThumb sub-component for automatic data-state sync |
| Table | Data table with header, body, rows, cells, and pagination |
| Tabs | Tabbed interface with keyboard navigation |
| Toggle | Pressed/active state with aria-pressed support |
| Tooltip | Brief informational popups with hover/focus triggers |
| Tree View | Hierarchical expand/collapse, selection, and checkbox state management |
Services
| Service | Description |
|---|---|
IPortalService |
Two-layer portal management with Container and Overlay categories |
IFocusManager |
Focus trapping and restoration for overlays |
IPositioningService |
Floating UI positioning with auto-update |
IKeyboardShortcutService |
Global keyboard shortcut registration and management |
DropdownManagerService |
Coordinates open/close state across multiple dropdowns |
API Reference
Accordion
<BbAccordion Type="AccordionType.Single" Collapsible="true" DefaultValue="item-1">
<BbAccordionItem Value="item-1">
<BbAccordionTrigger>Section 1</BbAccordionTrigger>
<BbAccordionContent>Content 1</BbAccordionContent>
</BbAccordionItem>
</BbAccordion>
| Parameter | Type | Default | Description |
|---|---|---|---|
Type |
AccordionType |
Single |
Single (one item open) or Multiple (many items open) |
Collapsible |
bool |
false |
When Single, allows closing all items |
Checkbox
<BbCheckbox @bind-Checked="isChecked" Indeterminate="@isIndeterminate">
<BbCheckboxIndicator />
</BbCheckbox>
| Parameter | Type | Default | Description |
|---|---|---|---|
Checked |
bool |
false |
Checked state |
Indeterminate |
bool |
false |
Shows partial/mixed state |
BbCheckboxIndicator renders the appropriate check or indeterminate SVG icon automatically based on parent state:
| Parameter | Type | Default | Description |
|---|---|---|---|
ChildContent |
RenderFragment? |
null |
Custom content instead of default icons |
Size |
int |
14 |
SVG icon size in pixels |
StrokeWidth |
int |
3 |
SVG stroke width |
Select
<BbSelect TValue="string" @bind-Value="selected" @bind-Open="isOpen">
<BbSelectTrigger>
<BbSelectValue Placeholder="Choose..." />
</BbSelectTrigger>
<BbSelectContent>
<BbSelectItem Value="@("a")" Text="Option A" />
<BbSelectItem Value="@("b")" Text="Option B" />
</BbSelectContent>
</BbSelect>
Select uses [CascadingTypeParameter] — child components infer TValue from the parent. Supports ItemClass for parent-level item styling.
| Parameter | Type | Default | Description |
|---|---|---|---|
Value |
TValue? |
— | Selected value (two-way bindable) |
Open |
bool |
false |
Open state (two-way bindable) |
ItemClass |
string? |
null |
CSS classes cascaded to all BbSelectItem children |
Dialog
<BbDialog @bind-Open="isOpen">
<BbDialogTrigger>Open</BbDialogTrigger>
<BbDialogPortal>
<BbDialogOverlay />
<BbDialogContent>
<BbDialogTitle>Title</BbDialogTitle>
<BbDialogDescription>Description</BbDialogDescription>
<BbDialogClose>Close</BbDialogClose>
</BbDialogContent>
</BbDialogPortal>
</BbDialog>
Sheet
<BbSheet>
<BbSheetTrigger>Open</BbSheetTrigger>
<BbSheetPortal>
<BbSheetOverlay />
<BbSheetContent Side="SheetSide.Right">
<BbSheetTitle>Title</BbSheetTitle>
<BbSheetDescription>Description</BbSheetDescription>
<BbSheetClose>Close</BbSheetClose>
</BbSheetContent>
</BbSheetPortal>
</BbSheet>
| Parameter | Type | Default | Description |
|---|---|---|---|
Side |
SheetSide |
Right |
Top, Right, Bottom, Left |
Popover
<BbPopover>
<BbPopoverTrigger>Open</BbPopoverTrigger>
<BbPopoverContent Side="PopoverSide.Bottom" Align="PopoverAlign.Center">
Content here
</BbPopoverContent>
</BbPopover>
| Parameter | Type | Default | Description |
|---|---|---|---|
Side |
PopoverSide |
Bottom |
Top, Right, Bottom, Left |
Align |
PopoverAlign |
Center |
Start, Center, End |
CloseOnEscape |
bool |
true |
Close when Escape key pressed |
CloseOnClickOutside |
bool |
true |
Close when clicking outside |
Tooltip
<BbTooltip DelayDuration="700" HideDelay="0">
<BbTooltipTrigger>Hover me</BbTooltipTrigger>
<BbTooltipContent>Tooltip text</BbTooltipContent>
</BbTooltip>
| Parameter | Type | Default | Description |
|---|---|---|---|
DelayDuration |
int |
700 |
Milliseconds before showing |
HideDelay |
int |
0 |
Milliseconds before hiding |
HoverCard
<BbHoverCard OpenDelay="700" CloseDelay="300">
<BbHoverCardTrigger>Hover for preview</BbHoverCardTrigger>
<BbHoverCardContent>Rich preview content</BbHoverCardContent>
</BbHoverCard>
| Parameter | Type | Default | Description |
|---|---|---|---|
OpenDelay |
int |
700 |
Milliseconds before showing |
CloseDelay |
int |
300 |
Milliseconds before hiding |
Dropdown Menu
<BbDropdownMenu ItemClass="px-2 py-1.5 cursor-pointer rounded hover:bg-accent">
<BbDropdownMenuTrigger>Menu</BbDropdownMenuTrigger>
<BbDropdownMenuContent>
<BbDropdownMenuItem>Cut</BbDropdownMenuItem>
<BbDropdownMenuItem>Copy</BbDropdownMenuItem>
<BbDropdownMenuItem Href="https://example.com" Target="_blank">Visit Site</BbDropdownMenuItem>
<BbDropdownMenuCheckboxItem @bind-Checked="isEnabled">Enable</BbDropdownMenuCheckboxItem>
</BbDropdownMenuContent>
</BbDropdownMenu>
| Parameter | Type | Default | Description |
|---|---|---|---|
ItemClass |
string? |
null |
CSS classes cascaded to all menu items |
BbDropdownMenuItem supports Href and Target for link items — renders as <a> when Href is set.
Switch
<BbSwitch @bind-Checked="isEnabled" class="relative h-6 w-11 rounded-full bg-input">
<BbSwitchThumb class="pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg" />
</BbSwitch>
BbSwitchThumb automatically syncs data-state ("checked" / "unchecked") from the parent via cascading parameter.
Radio Group
<BbRadioGroup TValue="string" @bind-Value="selected" ItemClass="flex items-center gap-2">
<BbRadioGroupItem Value="@("a")">Option A</BbRadioGroupItem>
<BbRadioGroupItem Value="@("b")">Option B</BbRadioGroupItem>
</BbRadioGroup>
| Parameter | Type | Default | Description |
|---|---|---|---|
ItemClass |
string? |
null |
CSS classes cascaded to all radio items |
Tabs
<BbTabs DefaultValue="tab1" Orientation="TabsOrientation.Horizontal"
ActivationMode="TabsActivationMode.Automatic">
<BbTabsList>
<BbTabsTrigger Value="tab1">Tab 1</BbTabsTrigger>
</BbTabsList>
<BbTabsContent Value="tab1">Content</BbTabsContent>
</BbTabs>
| Parameter | Type | Default | Description |
|---|---|---|---|
Orientation |
TabsOrientation |
Horizontal |
Horizontal, Vertical |
ActivationMode |
TabsActivationMode |
Automatic |
Automatic (on focus), Manual (on click) |
Table
<BbTable TData="Person">
<BbTableHeader>
<BbTableRow>
<BbTableHeaderCell>Name</BbTableHeaderCell>
<BbTableHeaderCell>Email</BbTableHeaderCell>
</BbTableRow>
</BbTableHeader>
<BbTableBody>
@foreach (var person in people)
{
<BbTableRow>
<BbTableCell>@person.Name</BbTableCell>
<BbTableCell>@person.Email</BbTableCell>
</BbTableRow>
}
</BbTableBody>
</BbTable>
| Parameter | Type | Default | Description |
|---|---|---|---|
SelectionMode |
SelectionMode |
None |
None, Single, Multiple |
SortDirection |
SortDirection |
None |
None, Ascending, Descending |
Portal Architecture
Primitives use a two-layer portal system for rendering overlay content:
- Container portals (
PortalCategory.Container): Dialog, Sheet — full-screen overlays - Overlay portals (
PortalCategory.Overlay): Popover, Select, Dropdown, Tooltip, HoverCard — positioned floating content
Each category has its own host (BbContainerPortalHost, BbOverlayPortalHost), so opening a tooltip doesn't cause Dialog portals to re-render. BbPortalHost is a convenience wrapper that renders both.
BbFloatingPortal keeps content mounted in the DOM when closed (ForceMount defaults to true), hidden via CSS. A data-state attribute ("open" / "closed") on the portal content enables CSS animations.
Controlled vs Uncontrolled
All stateful primitives support both controlled and uncontrolled modes:
Uncontrolled (Component manages its own state)
<BbDialog>
<BbDialogTrigger>Open</BbDialogTrigger>
<BbDialogPortal>
<BbDialogOverlay />
<BbDialogContent>Content</BbDialogContent>
</BbDialogPortal>
</BbDialog>
Controlled (Parent component manages state)
<BbDialog @bind-Open="isDialogOpen">
<BbDialogTrigger>Open</BbDialogTrigger>
<BbDialogPortal>
<BbDialogOverlay />
<BbDialogContent>
<button @onclick="() => isDialogOpen = false">Close</button>
</BbDialogContent>
</BbDialogPortal>
</BbDialog>
@code {
private bool isDialogOpen = false;
}
Design Philosophy
BlazorBlueprint.Primitives follows the "headless component" pattern popularized by Radix UI and Headless UI:
- Separation of Concerns: Primitives handle behavior and accessibility; you handle the design
- Composability: Build complex components by composing simple primitives
- No Style Opinions: Zero CSS included — bring your own design system
- Accessibility by Default: ARIA attributes and keyboard navigation built-in
When to Use
Use BlazorBlueprint.Primitives when:
- Building a custom design system from scratch
- Need complete control over component styling
- Want to match a specific brand or design language
- Integrating with existing CSS frameworks or design tokens
Consider BlazorBlueprint.Components when:
- Want beautiful defaults with shadcn/ui design
- Prefer zero-configuration setup with pre-built CSS
- Need to ship quickly without custom styling
Documentation
For full documentation, examples, and API reference, visit:
License
Apache License 2.0 - see LICENSE for details.
Contributing
Contributions are welcome! Please see our Contributing Guide.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.AspNetCore.Components.Web (>= 8.0.14)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on BlazorBlueprint.Primitives:
| Package | Downloads |
|---|---|
|
BlazorBlueprint.Components
Pre-styled Blazor components built with shadcn/ui design and Tailwind CSS. Beautiful defaults that you can customize to match your brand. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.5.0 | 238 | 3/11/2026 |
| 3.4.0 | 883 | 3/6/2026 |
| 3.3.0 | 404 | 3/4/2026 |
| 3.2.0 | 969 | 2/28/2026 |
| 3.1.2 | 122 | 2/28/2026 |
| 3.1.1 | 106 | 2/28/2026 |
| 3.1.0 | 110 | 2/28/2026 |
| 3.0.1 | 733 | 2/17/2026 |
| 3.0.0 | 119 | 2/17/2026 |
| 2.3.2 | 460 | 2/10/2026 |
| 2.3.1 | 94 | 2/10/2026 |
| 2.2.0 | 397 | 2/8/2026 |
| 2.1.1 | 159 | 2/7/2026 |
| 2.1.0 | 92 | 2/7/2026 |
| 2.0.0 | 298 | 2/2/2026 |
## What's New in v3.5.0
### New Components
- **AlertDialog** — Modal dialog with `role="alertdialog"` that prevents dismiss via Escape or overlay click, ideal for destructive confirmations
- **ContextMenu** — Right-click triggered menu with `role="menu"`, full keyboard navigation via arrow keys, and positioning support
- **Progress** — Determinate and indeterminate progress bar with `role="progressbar"` and `aria-valuenow`/`aria-valuemin`/`aria-valuemax`
- **Separator** — Accessible separator with `role="separator"` or `role="none"` (decorative mode), horizontal and vertical orientation
- **Slider** — Range input with `role="slider"`, keyboard navigation (arrows, Home, End, PageUp, PageDown), and JS-powered drag interaction
- **Toggle** — Accessible toggle button with `aria-pressed`, supporting controlled and uncontrolled state
- **ToggleGroup** — Single or multiple selection toggle group with roving tabindex and keyboard navigation
### New Features
- **Localization** — New `IBbLocalizer` interface with `DefaultBbLocalizer` implementation, enabling `IStringLocalizer` integration for all component chrome strings
- **DataGrid hierarchical tree** — `HierarchyManager` utility for nested, self-referencing, and lazy-loaded tree data with expand/collapse, per-level sorting, child pagination, and filter-aware hierarchy display
- **DataGrid cascading hierarchy selection** — `HierarchySelectionMode.Cascade` for parent-child checkbox cascading with indeterminate state
- **DataGrid hierarchy filter modes** — `HierarchyFilterMode` enum (`ShowMatchedSubtree` / `ShowMatchedOnly`) to control how filtering treats descendants
- **Filtering: finer time units** — Added `Hours`, `Minutes`, and `Seconds` to `InLastPeriod` enum for finer-grained date/time filtering
- **BbPrimitiveBase** — Shared base class with `MergeStyles` and `FilteredAttributes` helpers to reduce duplication across primitives
- **BbTablePagination** — Added string parameters for aria labels to support localization
- **Checkbox** — Added `Required` parameter with `aria-required` support
- **RadioGroup** — Added `Required` parameter with `aria-required` support
- **Popover** — Added configurable `Role` parameter (changed default from `group` to `dialog`)
- **HoverCard trigger** — Added `tabindex="0"` for keyboard focusability
### Bug Fixes
- **DataGrid** — Respect initial `Visible` property on columns so `Visible=false` columns are hidden on first render
- **DataGrid** — Fix column filtering for nullable types; add `DateOnly` and `DateTimeOffset` support in filter expressions
- **DataGrid** — Auto-generate enum filter dropdown options when `FilterOptions` is not explicitly provided
- **DataGrid** — Keep table header visible when filters produce empty results so users can clear filters
- **DataGrid** — Yield keyboard navigation to interactive children (Combobox, MultiSelect) inside cell templates
- **Select** — Fix displaying value instead of text on initial load when using `DisplayTextSelector`
- **Checkbox** — Fix spacebar toggle regression caused by synthetic click double-toggle
- **ContextMenu** — Fix re-open at new position via z-index layering on trigger
- **ContextMenu** — Fix keyboard navigation on re-open by re-initializing keyboard module
- **Switch** — Remove non-standard Enter key handling (Space only per WAI-ARIA)
### Improvements
- **Popover** — Changed `role="group"` to `role="dialog"` for correct ARIA semantics
- **DropdownMenu** — Added `aria-labelledby` pointing to trigger on menu content
- **Tabs** — Filter arrow key navigation by orientation (horizontal: Left/Right, vertical: Up/Down)
- **Select trigger** — Replace blanket `preventDefault` with conditional handling
- **JS interop resilience** — Added `JSException` catch filters across all overlay components for graceful offline/disconnect handling
- **Floating portal** — Silently handle `JSException` in positioning and setup
- **Keyboard shortcuts JS** — Added null check for `event.target`
- **Click-outside JS** — Fixed `setTimeout` race condition in cleanup
- **Select JS** — Added bounds validation in `scrollIntoContainerView`
- **Positioning JS** — Removed unnecessary `!important` on top/left styles
- **Tree keyboard JS** — Improved interactive child detection and error handling
- **Async void elimination** — Replaced `async void` handlers with `async Task` in `BbPopoverContent`, `BbDropdownMenuContent`, `BbSelectContent`, and `BbTreeView`
- **BbSelectContent** — Fixed `DotNetObjectReference` overwrite using `??=` and added disposed guard to `JSInvokable` methods