Adliance.AspNetCore.Buddy.GuiKit
10.2.0.33
Prefix Reserved
dotnet add package Adliance.AspNetCore.Buddy.GuiKit --version 10.2.0.33
NuGet\Install-Package Adliance.AspNetCore.Buddy.GuiKit -Version 10.2.0.33
<PackageReference Include="Adliance.AspNetCore.Buddy.GuiKit" Version="10.2.0.33" />
<PackageVersion Include="Adliance.AspNetCore.Buddy.GuiKit" Version="10.2.0.33" />
<PackageReference Include="Adliance.AspNetCore.Buddy.GuiKit" />
paket add Adliance.AspNetCore.Buddy.GuiKit --version 10.2.0.33
#r "nuget: Adliance.AspNetCore.Buddy.GuiKit, 10.2.0.33"
#:package Adliance.AspNetCore.Buddy.GuiKit@10.2.0.33
#addin nuget:?package=Adliance.AspNetCore.Buddy.GuiKit&version=10.2.0.33
#tool nuget:?package=Adliance.AspNetCore.Buddy.GuiKit&version=10.2.0.33
Adliance.AspNetCore.Buddy.GuiKit
The GuiKit Buddy provides a set of UI components, tag helpers, and static assets (CSS, JS, fonts) for building consistent ASP.NET Core web applications.
Features
- Bundled and minified CSS and JavaScript assets
- Razor tag helpers for common UI components
- Application Insights and Azure Key Vault setup (via GuiKit.Infrastructure)
Setup
Application Insights and Azure Key Vault are set up by Adliance.AspNetCore.Buddy.GuiKit.Infrastructure, a dependency of GuiKit (see its README):
using Adliance.AspNetCore.Buddy.GuiKit.Infrastructure.Extensions;
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddKeyVaultIfConfigured(builder.Environment);
builder.Services.AddApplicationInsightsIfConfigured();
Serve static files with app.UseGuiKitStaticFiles() instead of app.UseStaticFiles(), so browsers cache them:
files requested with a version (?v=..., like the CSS and JavaScript of GuiKit's layouts) for a year, and GuiKit's
fonts and images for a week. The version is the app's InformationalVersion (AppVersion.Current, which the app's
own files can use as well: href="~/styles.css?v=@AppVersion.Current"), so a new build of the app (eg. with an
updated GuiKit) loads them again. During development, browsers check every file for changes instead.
Layout
GuiKit ships a base layout, _AgkLayout, with GuiKit's CSS and JavaScript, FontAwesome, the Application Insights
snippet and the htmx configuration for a Content Security Policy. An app's own layout builds on it:
@{
Layout = "_AgkLayout";
}
@section Header
{
<title>My App</title>
}
<partial name="_Navigation"/>
<main>
@RenderBody()
</main>
Its sections are Header (additional content of <head>) and Scripts (additional scripts at the end of <body>),
both optional. AgkStylesheets and AgkScripts replace GuiKit's own min.css/min.js, eg. with a theme's bundle
that already contains them - the MADx layouts (_MadxCommonLayout, _MadxLoginLayout) build on _AgkLayout that way.
The navigation on the left (eg. the _Navigation partial above) is an <agk-sidebar>. On small screens, it collapses
into a header with a hamburger button that opens it. The app's version is shown below its footer automatically. Icons
(<i class="fa fa-...">) in front of an item's text are sized to the text and all have the same width, so the texts
line up. Sub-items (a nested <ul>) are indented by the width of such an icon, so they line up with the text of an
item with an icon.
<agk-sidebar>
<agk-sidebar-header>My App</agk-sidebar-header>
<agk-sidebar-main>
<b>Pages</b>
<ul>
<li><a asp-page="/Index"><i class="fa fa-house"></i>Home</a></li>
<li>
<i class="fa fa-gear"></i>Settings
<ul>
<li><a asp-page="/Users">Users</a></li>
</ul>
</li>
</ul>
</agk-sidebar-main>
<agk-sidebar-footer>
<ul>
<li><a asp-page="/Logout"><i class="fa fa-right-from-bracket"></i>Logout</a></li>
</ul>
</agk-sidebar-footer>
</agk-sidebar>
Tag Helpers
Add the tag helpers to your _ViewImports.cshtml:
@addTagHelper *, Adliance.AspNetCore.Buddy.GuiKit
| Tag Helper | Description |
|---|---|
<agk-breadcrumbs> |
Renders breadcrumbs (eg. above the page title) of <agk-crumb>s (at least one), each with a text (plain text), an optional icon, an optional hint (plain text, shown muted after the text) and an optional link (href or asp-* routing; without one, it's only text). The last crumb is the current page. Other attributes of an <agk-crumb> (eg. class, title) are rendered on its link |
<agk-button> |
Renders a <button> with a text, an optional icon (icon-position left or right), a color (Primary, Secondary or Danger) and a size; supports asp-* routing (sets formaction). A submit button (and one with hx-post, hx-put, hx-patch or hx-delete) shows a spinner and is disabled while its form is submitted, also via htmx; show-loading="false" switches that off, eg. for a form that downloads a file. confirm="Delete the item?" asks that question in a modal before the button does its action (also before an htmx request) |
<agk-chart> |
Renders a chart with Apache ECharts (bundled); its options are the model (serialized to JSON, camelCase) or set in a <script> child, eg. <script>const options = { series: [...] };</script>. Razor values in the script must be serialized to JSON, without quotes: { name: @Json.Serialize(Model.Name) }, never '@Model.Name' (HTML encoding doesn't protect a JavaScript string). A string model isn't allowed |
<agk-chat> |
Renders a chat of <agk-chat-question> (right) and <agk-chat-answer> (left) bubbles; is-loading shows a typing indicator |
<agk-checkbox> |
Renders a labeled checkbox with an optional placeholder next to it, bound to a bool |
<agk-form-element> |
Renders a form element's label and help text around custom content |
<agk-input> |
Renders a labeled <input>, optionally with an icon and help text; <agk-button>s and <agk-link>s written into it are placed to the right of the input (and take on its size), or below it if there isn't enough room for both |
<agk-link> |
Renders a link (<a>) that looks like a button, with the same text, icon, color and size as <agk-button>; href or asp-* routing; confirm like on <agk-button>; disabled="true" renders it grayed out and without its target |
<agk-loading> |
Renders a loading indicator, with an optional text (plain text) |
<agk-modal> |
Renders a modal dialog (HTML popover) with a title, a close button and a dark backdrop; opened by a button with popovertarget="{id}"; content can be loaded via htmx (like <agk-panel>) each time it opens |
<agk-notification> |
Renders a notification/alert component |
<agk-pagination> |
Renders a pagination (eg. in a table's <tfoot>) of the current-page and max-page (starting at 1): a previous and a next arrow and up to 10 page numbers around the current page (with "..." markers if there are more), centered in a <tfoot>, linking to the current URL with the page in the query parameter page-parameter (default p, as page can't be bound in Razor Pages; other query parameters are kept); nothing is rendered for a single page. In content loaded via htmx (eg. an htmx-loaded <agk-panel>), the links load the page into the same container via htmx instead of reloading the entire page (hx-target overrides the container), showing a spinner instead of the clicked number or arrow while it loads; hx-method="Post" loads it with a POST request (with the antiforgery token and the values of the surrounding form, eg. a filter) instead of a GET |
<agk-panel> |
Renders a panel/card component with an optional title (plain text) and icon |
<agk-password> |
Renders a labeled password <input> with an eye icon inside it that toggles the password's visibility, optionally with an icon and help text; buttons written into it are placed to the right like in <agk-input> |
<agk-rating> |
Renders a labeled rating of 5 stars, bound to a nullable int; readonly="true" only displays it |
<agk-sidebar> |
Renders the navigation bar on the left (<nav>) of <agk-sidebar-header> (with the hamburger button for small screens), <agk-sidebar-main> (scrollable) and <agk-sidebar-footer>, all optional; the app's version (AppVersion.Current) is shown below the footer automatically, version overrides it ("" hides it) |
<agk-select> |
Renders a labeled <select>, optionally with an icon and help text; buttons written into it (between its <option>s) are placed to the right like in <agk-input> |
<agk-table> |
Renders a <table> of <agk-table-header> (<thead>, optional), <agk-table-body> (<tbody>, required) and <agk-table-footer> (<tfoot>, optional), each with <tr> rows as content. Rows of the body are highlighted on hover (hover-row="false" switches that off), and a click anywhere on a row follows the first link in that row, as if the link was clicked (incl. Ctrl/Cmd+click, htmx and confirm); links, buttons and form elements in the row still do their own thing (link-row="false" switches that off) |
<agk-tabs> |
Renders a card (like a panel) with a group of <agk-tab>s (at least one) in its header, each with a title (plain text) and an optional icon, of which the first (or the one with selected="true") is shown initially; the arrow keys, Home and End switch between them once one is focused. A tab's content is either written within it (switching tabs only shows and hides it), or loaded via htmx with hx-get or hx-post (and hx-target, hx-swap, hx-tag-name like <agk-panel>): the selected tab's with the page, the others' the first time they're shown, so it keeps its state when switching tabs (hx-trigger overrides that). Other attributes of an <agk-tab> (eg. class) are rendered on its content's element, id sets its id (eg. for hx-target) |
<agk-textarea> |
Renders a labeled <textarea>, optionally with an icon and help text |
<agk-upload> |
Renders a labeled file upload (<input type="file">), optionally with an icon and help text |
<agk-title> |
Renders a styled page title of text (plain text); its content (may contain HTML) is shown below it |
Styling
Layout
<section>(within<main>) lays out panels next to each other,<fieldset>does the same for form elements within a panel. Up to 4 children share a row equally (1 child takes the full width, 2 half of it, 3 a third, ...). How many columns there are at most depends on the width of the section/fieldset itself (container queries), not on the width of the screen.- Fieldsets are spaced from each other and from form elements, buttons and paragraphs that follow them anywhere (eg.
in a
<form>within a tab), not only in panels and sections. - A
<select>written by hand (eg. into<agk-form-element>) gets the same dropdown arrow as<agk-select>when it's wrapped into a<div class="select">; without it, it keeps the browser's own arrow.
Page transitions
Navigating between pages of the app shows a subtle transition: the nav stays in place and the content fades out and
back in. It uses the browser's cross-document
view transitions (no JavaScript needed); in
browsers without support, and for users who reduce motion in their OS settings, pages simply switch as before. It can
be tuned with --agk-page-transition-duration, or switched off with
@view-transition { navigation: none; } in the app's own CSS.
Content Security Policy
GuiKit works with a strict Content Security Policy, without 'unsafe-inline' or 'unsafe-eval':
app.UseGuiKitContentSecurityPolicy()sends a strict policy with every response (register it before static files). It only allows the app's own origin plus the request's nonce for inline scripts and styles, and Application Insights if it's configured. More sources can be allowed, or the policy tried out without blocking anything:app.UseGuiKitContentSecurityPolicy(options => { options.Add("img-src", "https://images.example.com"); options.ReportOnly = true; });- Apps that build their own policy use
HttpContext.GetGuiKitCspNonce()(inAdliance.AspNetCore.Buddy.GuiKit.Extensions), a random nonce for the current request, eg.script-src 'self' 'nonce-{nonce}'; style-src 'self' 'nonce-{nonce}'. - Every inline
<script>in a view that uses GuiKit's tag helpers automatically gets that nonce, and so do GuiKit's own inline scripts (eg. of<agk-chart>, or the Application Insights snippet). - htmx inserts scripts and styles of the content it loads, which need the nonce as well - the MADx layouts already
configure this, other layouts add
<meta name="htmx-config" content='{"inlineScriptNonce":"@Context.GetGuiKitCspNonce()","inlineStyleNonce":"@Context.GetGuiKitCspNonce()"}'/>. - GuiKit itself sets no inline styles (a chart's height, for example, is set by its JavaScript).
Theming
All styles are built from CSS variables, which are defined (and documented) in
css/tokens.css. They are named --agk-{component}-{property}[-{variant}], eg.
--agk-button-background-hover or --agk-input-padding-block-lg. Variables starting with --_ are private to a
component and not meant to be overridden.
Override them on :root, eg.:
:root {
--agk-color-primary: #004488;
--agk-button-radius: 0;
}
All GuiKit styles are in cascade layers
(agk.reset, agk.tokens, agk.base, agk.components, agk.layout, agk.overlays, agk.theme). CSS of an app that isn't in a
layer always wins over them, regardless of its specificity - so no !important is needed to override GuiKit styles.
Themes that are distributed as a package (like the MADx one) put their overrides into @layer agk.theme { ... }.
UI/UX guidelines
See UX-GUIDELINES.md for how views built with GuiKit should look and behave.
Changelog
See CHANGELOG.md for the changes in each release.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
-
net10.0
- Adliance.AspNetCore.Buddy.GuiKit.BuildTasks (>= 10.0.0.10)
- Adliance.AspNetCore.Buddy.GuiKit.Infrastructure (>= 10.2.0.33)
- Adliance.Buddy.CodeStyle (>= 8.2.0.1)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Adliance.AspNetCore.Buddy.GuiKit:
| Package | Downloads |
|---|---|
|
Adliance.AspNetCore.Buddy.GuiKit.Madx
Library of CSS, JavaScript, TagHelpers and layouts for a commonly shared Adliance UI, but themed for MADx. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 10.2.0.33 | 124 | 10/28/2026 |
| 10.2.0.32 | 150 | 10/26/2026 |
| 10.2.0.31 | 109 | 10/26/2026 |
| 10.2.0.30 | 106 | 10/26/2026 |
| 10.2.0.29 | 100 | 10/26/2026 |
| 10.2.0.28 | 108 | 10/26/2026 |
| 10.2.0.27 | 114 | 10/25/2026 |
| 10.2.0.26 | 121 | 10/23/2026 |
| 10.2.0.25 | 110 | 10/23/2026 |
| 10.2.0.24 | 110 | 10/23/2026 |
| 10.2.0.23 | 111 | 10/19/2026 |
| 10.2.0.22 | 127 | 10/19/2026 |
| 10.2.0.21 | 159 | 10/13/2026 |
| 10.2.0.20 | 155 | 10/5/2026 |
| 10.2.0.19 | 112 | 10/5/2026 |
| 10.2.0.18 | 116 | 10/5/2026 |
| 10.2.0.14 | 182 | 10/1/2026 |
| 10.2.0.13 | 115 | 10/1/2026 |
| 10.2.0.12 | 118 | 10/1/2026 |
| 10.2.0.11 | 121 | 9/30/2026 |
# Changelog
Notable changes to the GuiKit packages (`Adliance.AspNetCore.Buddy.GuiKit`, `.Madx` and `.Infrastructure`, which are
always published together with the same version). Newest first.
## 2026-10-28
- `<agk-checkbox>`: clicking the help text toggles the checkbox, like clicking its placeholder (the help text is
rendered as a `<label>` of the checkbox instead of a `<span>`).
- `<agk-notification>`: the icon is as high as the notification's text, up to `--agk-notification-icon-size` (reached
with two lines of text), so a notification with a short text isn't higher than its text anymore. The icon's column
keeps its width, and a smaller icon is placed next to the text, with a space after it that shrinks along with it.
- `--agk-notification-icon-size` is two lines of text by default (`--agk-font-size` times `--agk-line-height`, ie.
28px), instead of 48px, so the icon's column is narrower as well.
## 2026-10-26
- A row of buttons and links that wraps into several lines (directly in a panel, tab, `<main>` or a `<p>`) has a small
gap between its lines; they touched before.
- Buttons and links in an `<agk-input>`, `<agk-password>` or `<agk-select>` wrap below the field if there isn't
enough room for both (eg. a large field in a narrow column), instead of squeezing the field to nothing.
- Paragraphs, lists and other blocks in an `<agk-notification>` are spaced evenly, instead of by the browser's own
margins.
- `<agk-chart>`: gauges use GuiKit's chart colors for their title, value and scale (they were dark on a dark
background).
- Second-level navigation items in the nav have less vertical padding, to match their smaller font size.
- Fixed the spacing of a nav item without a link that has sub-items: the next item was spaced too far from it and the
sub-items were indented more than below an item with a link.
- Fixed the spacing between a nav item with a link and its sub-items: it was larger than below an item without a link.
- The modal of `confirm` (on `<agk-button>` and `<agk-link>`) shows the question as its content, below an empty title,
instead of as its title.
- Icons (`<i class="fa fa-...">`) in nav items are as large as the item's text and all have the same width, so the
texts line up.
- Sub-items in the nav are indented by the width of an icon (instead of twice `--agk-nav-padding`), so they line up
with the text of an item with an icon.
- Fixed the spacing below a panel title when a button or link (`<agk-button>`, `<agk-link>`) follows it directly: it
was twice as large as before a paragraph.
- Fixed buttons and links (`<agk-button>`, `<agk-link>`) next to each other directly in a panel, tab or `<main>`
(without a `<p>` around them): the whole row was pushed down by the spacing between the elements.
## 2026-10-25
- `UX-GUIDELINES.md` has new rules for the content of `<agk-title>`, when to use `<agk-breadcrumbs>`, `[From*]`
attributes on action method parameters and where tests go.
## 2026-10-23
- Added `<agk-breadcrumbs>` with `<agk-crumb>` children, each with a `text`, an optional `icon`, `hint` (shown muted
after the text) and link (`href` or `asp-*`). New CSS variables `--agk-breadcrumbs-font-size`,
`--agk-breadcrumbs-color-current`, `--agk-breadcrumbs-hint-color`, `--agk-breadcrumbs-separator`,
`--agk-breadcrumbs-separator-color` and `--agk-breadcrumbs-gap`.
- The "choose file" button of `<agk-upload>` has the secondary button color instead of the primary one.
- `<agk-button>`s and `<agk-link>`s written into `<agk-input>`, `<agk-password>` or `<agk-select>` are placed to the
right of the field, with the label, help text and validation message around both. They take on the field's `size`.
- Two fieldsets (and a fieldset and a form element, button or paragraph after it) are spaced from each other anywhere,
eg. in a `<form>` within a tab - before, only panels and sections spaced them.
- Links in `<agk-notification>`, in the page title and in its text (`<agk-title>`, or a `<h1>`/`<hgroup>` directly
in `<main>`) have the color of the surrounding text and are always underlined, instead of the link color.
- `UX-GUIDELINES.md` is grouped by topic and has new rules for `<fieldset>` in panels and tabs, buttons inside a
field's tag helper, `nameof` in action links, view models and `TempData`/`ViewData`.
## 2026-10-19
- Added `<agk-tabs>`, a card (like a panel) with `<agk-tab>` children in its header, whose content is either written
within them or loaded via htmx the first time a tab is shown. New CSS variables `--agk-tabs-background`,
`--agk-tabs-font-size`, `--agk-tabs-padding-block`, `--agk-tabs-padding-inline`, `--agk-tabs-color`,
`--agk-tabs-color-selected`, `--agk-tabs-indicator-color`, `--agk-tabs-indicator-height` and
`--agk-tabs-content-padding`.
- Fixed XSS: `<agk-title text>`, `<agk-panel title>` and `<agk-loading text>` were rendered as HTML, and the `icon` of
`<agk-panel>` and `<agk-notification>` wasn't encoded either - so values from a database or a user could inject
scripts. All of them are HTML-encoded now, like all other attributes already were.
- **Breaking:** `<agk-title text>`, `<agk-panel title>` and `<agk-loading text>` are plain text. HTML in them is shown
as text, and HTML entities as they are written: replace eg. `title="Terms & Conditions"` with
`title="Terms & Conditions"`. For formatted text below a page title, use the content of `<agk-title>`.
- **Breaking:** `<agk-chart model>` doesn't accept a string with JavaScript anymore (it throws). Move the JavaScript
into a `<script>` child of `<agk-chart>`. Razor values in that script have to be serialized to JSON, without quotes:
`{ name: @Json.Serialize(Model.Name) }`, never `'@Model.Name'`.
## 2026-10-13
- Added `<agk-table>` with `<agk-table-header>`, `<agk-table-body>` and `<agk-table-footer>`: rows are highlighted on
hover (`hover-row`) and a click on a row follows its first link (`link-row`), both on by default. New CSS variable
`--agk-table-row-background-hover`.
- Added UI/UX guidelines for views built with GuiKit (`UX-GUIDELINES.md`, shipped with the package).
## 2026-10-05
- Added `<agk-pagination>`.
- Added `<agk-sidebar>` for a navigation on the left.
- Buttons and pagination links show a spinner while loading.
- Added a `confirm` attribute to delete buttons for an "are you sure" dialog.
- Fixed the hover of `<agk-rating>` (and other controls based on unstyled buttons) showing the button hover background.
## 2026-10-01
- Added `<agk-password>`, an input with a toggle to show the password.
- Buttons support different colors.
- The MADx login layout is responsive.
- **Breaking:** AppInsights and KeyVault extensions moved to the new package `Adliance.AspNetCore.Buddy.GuiKit.Infrastructure`
(referenced by GuiKit, so no new package reference is needed; change `using` directives to `Adliance.AspNetCore.Buddy.GuiKit.Infrastructure[.Extensions]`).
## 2026-09-30
- Restructured the CSS with consistent `--agk-*` variable names and cascade layers.
- Added a common base layout `_AgkLayout`; the MADx layouts are based on it.
- Added `<agk-button>`, `<agk-modal>`, `<agk-chart>`, `<agk-upload>`, `<agk-checkbox>` and `<agk-chat>`.
- Selects support sizes; ratings support `readonly`; chat bubbles have a loading animation.
- Page transitions.
- Support for a strict CSP by default.
- `app.UseGuiKitStaticFiles()` for proper caching of static assets.
- Accessibility improvements and improved form and button styling.
- The MADx package depends on the GuiKit package of the same version (published together).
## 2026-09-23
- Configuration order with Key Vault: appsettings.json, Key Vault, environment variables,
appsettings.{Environment}.json - so environment variables can override Key Vault secrets.
## 2026-09-09
- Added `<agk-rating>`.
- Added `<agk-textarea>`, like `<agk-input>`.
## 2026-08-20
- `<agk-loading>` supports a `text` attribute and arbitrary HTML attributes.
- Table header and footer have correct border radii.
## 2026-08-19
- Inputs support sizes.
## 2026-08-18
- Added `AddKeyVaultIfConfigured()`, which adds Azure Key Vault as a configuration source if a `KeyVault` connection
string is configured.
- MADx: fixed text decoration of header links; adjusted margins of the login page.
## 2026-08-10
- MADx: restructured the login layout; it sets `ViewData["Version"]` to the assembly version.
- MADx: styling of ASP.NET validation errors (`.field-validation-error`).
- The text decoration of links is configurable via a CSS variable.
## 2026-08-06
- MADx: moved the logo a little more to the top.
## 2026-08-05
- Added `<agk-select>`.
- Form elements inside a `<fieldset>` are laid out side by side.
- Form controls use `color-scheme: dark` for better native browser controls.
- Fixed missing static web assets in the MADx package.
## 2026-08-04
- Added the analyzer that flags tag helper attributes set to their default value.
- Upgraded FontAwesome to 7.3.1; its CSS is no longer bundled into `min.css` (fixes relative font paths).
- `<agk-panel>` loads its htmx content on `load, submit` by default.
- Fixed builds on Windows.
## 2026-07-23
- Fixed `hx-post` inside panels; it now sends a CSRF token.
- `<agk-loading>` no longer has a text (added again on 2026-08-20).
## 2026-07-22
- More htmx settings for panels.
## 2026-07-20
- `<agk-loading>` supports a status text.
- Improved margins of elements inside panels.
- Added a placeholder login layout.
## 2026-07-18
- Initial version, a copy of the previous public version of GuiKit.
- Added the MADx theme package.
- Added `<agk-input>` and `<agk-form-element>` for reusable form elements.
- Improved button styles.