# Upgrading

> Plainkit 0.28.0. Generated by scripts/build-skills.mjs from CHANGELOG.md and core/tools/api-surface.mjs. Do not edit: change the source and run the generator.

This is a blast-radius recipe, not a changelog readout: the goal is a checklist of what to change in *this app*, not a summary of what Plainkit changed in the abstract.

## 1. Find the two versions

The installed version is the `Version` of the `PackageReference Include="PlainKit.Blazor"` in the app's `.csproj`. The target is the version you are moving to (latest release unless the user names one).

## 2. Pull what changed between them

`CHANGELOG.md` (`https://github.com/skulmunkie/plainkit/blob/main/CHANGELOG.md`, not shipped in the package) has one section per released version, with `### Breaking`, `### Removed`, `### Changed`, `### Fixed`, `### Added` and `### Notes` subsections; every entry names the affected element, component or export and its issue number. Read every version's section between the installed one and the target (a target that is an unreleased build of `main` or `next` has its newest entries only as the fragments in the repository's `changelog/unreleased/` folder: read those too), and pull out `Breaking`/`Removed`/`Changed` entries first (these are the ones that can break a build or change behaviour silently) and `Added` second (opportunities, not urgent). A running app already surfaces one more signal for free: an element or a Blazor component that is deprecated but not yet removed logs a one-time console/ILogger warning (`js/deprecation.js`) naming what to use instead — check the app's own logs, not just the changelog, for anything still on borrowed time.

## 3. Cross-reference against this app's own code

A changelog entry only matters if the app uses what it names. For every tag, component, parameter, event or slot the step above turned up, search the app itself (not the Plainkit source) for it — grep for the Razor component name or the element tag, the parameter name, the event name. The output of this step is specific: "this app uses `PkTable`'s `EmptyContent` in 3 files, and the changelog says it was renamed," not "`EmptyContent` was renamed."

## 3b. Let the app tell you about removed CSS classes

Removed classes (retired class-based components, removed `u-*` utilities) are silent: nothing fails, the styling just disappears, and a grep for names you did not know to look for misses them. `js/compat-warn.js` is an opt-in module (zero cost unless imported): `import { checkCompatClasses } from './plainkit/js/compat-warn.js'; checkCompatClasses();` in a dev build logs each retired or removed class it finds in the running app, once, with a replacement (scope `compat`, warn level). Load the app's main pages with it on and add every warning to the checklist. Do not ship the call to production.

## 4. Produce a checklist, most severe first

Group the matches from step 3 by severity (breaking first), each with the file(s) it appears in — the shape a person or another agent can work through and tick off, not a wall of prose.

## 5. Say what is mechanical and what needs a judgment call

A renamed parameter or component is a mechanical find-and-replace: make the change yourself. A removed component with no direct replacement, or a behaviour change with no compile-time signal, needs a person to decide: flag it on the checklist instead of guessing.

## 5b. Moving from an earlier release: tier namespaces (Blazor)

In this release the generated components of the component, page and shell tiers live in `PlainKit.Blazor.Components` (`PkTabs`, `PkKanban`, `PkDetailLayout`, `PkDataTable<TItem>` ...), `PlainKit.Blazor.Pages` (`PkWizardPage`, `PkRecordPage`, `PkListPage<TItem>` ...) and `PlainKit.Blazor.Shells` (`PkAppShell`); base elements (`PkButton`, `PkCard`, `PkInput` ...) stay in `PlainKit.Blazor`. Razor resolves a tag only through an `@using`, so a build full of RZ10012 ("add a @using directive"; a *warning*, so the build may still succeed and render nothing) means: add `@using PlainKit.Blazor.Components`, `@using PlainKit.Blazor.Pages` and `@using PlainKit.Blazor.Shells` to `_Imports.razor` (keep `@using PlainKit.Blazor`). This is mechanical; do it first. The generic `PkDataTable<TItem>` and `PkListPage<TItem>` need these lines for every tag.

C# needs nothing for the common cases: the package ships `buildTransitive/PlainKit.Blazor.targets`, which adds the three namespaces as global usings, so `typeof(PkTabs)`, `@ref` fields, code-behind and `OpenComponent` resolve through the namespace alone (generic components included). The same file adds an explicit alias per moved non-generic component (`PkTabs` for `PlainKit.Blazor.Components.PkTabs`); the aliases are redundant with the namespace usings, kept for explicitness for one minor version and then removed. If a C# file still does not resolve a moved type, add `using PlainKit.Blazor.Components;` (or `.Pages`, `.Shells`) to it.

## 5c. Names that were removed or renamed (Blazor)

A removed name has no obsolete alias. In C# the app stops compiling (CS0103, CS0115, CS0117), which is the signal. A removed component used as a Razor tag is only a *warning*: RZ10012 "Found markup element with unexpected name", the build can look green and the page renders an unknown element, so turn RZ10012 into an error while you upgrade (`<WarningsAsErrors>RZ10012</WarningsAsErrors>` in the .csproj) and search the app for each name in the left column; the right column is the replacement.

| Old | Now |
| --- | --- |
| `PkDataList<TItem>`, its `Items`, `CurrentId` and `LoadAllIds` | `PkDataTable<TItem>` with `Load` (a `PkListRequest` in, a `PkListResult<TItem>` of the page and the total out; a list you already hold goes in `PkListResult`), `CurrentRow`; for `LoadAllIds` run the bulk action against the query that `OnSelect` carries when the scope is `all` (`args.ToRequest()`) |
| `<PkRawTable>` | `<PkTable TItem="object">` with `HeadContent`, `ChildContent`, `FootContent` (same parameter names; see `table-raw-mode.md`) |
| `<PkFieldListRow>` (`Label`, `Value`, `SkipEmpty`, `When`) | plain `<dt>`/`<dd>` in `PkFieldList`: an empty `dd` hides its pair; `ShowEmpty` on the list for `SkipEmpty="false"`; `@if` for `When` |
| `PageBase.ShowBusyOverlay`, `BusyDelay`, `BusyMinTime`, `Clock` | `<PkLoadingOverlay Busy="@IsBusy" Delay="150" MinTime="300" Label="@BusyLabel">`: the overlay owns the timing; `PageBase` keeps only the busy count and label |
| `PkEmptyState.DescriptionContent` | `ChildContent` (a link back or a button goes in `ActionContent`) |
| `PkPageHeader` `Crumbs` drawing a `pk-breadcrumb` child | the same `Crumbs` parameter, but the `pk-breadcrumb` is now inside the header's shadow tree: a bUnit `Find("pk-breadcrumb")`, a browser test or a style that looks for it in the page DOM finds nothing (assert on the `crumbs` attribute, a JSON array of `{ label, href }`, instead) |
| `PkCardMenu` built by hand from `PkDropdown` and an icon `PkButton` | `PkCardMenu` (generated from `pk-card-menu`); the generated components now live in tier namespaces, see the previous step |

## 6. Report what you found back upstream

An upgrade often turns up something Plainkit itself should fix. File it on `https://github.com/skulmunkie/plainkit/issues` instead of leaving it as a private workaround. File when you find: a bug during or after the upgrade; a gap or missing feature the app works around; a deprecation with no clear replacement; or an inaccuracy in the docs or these skills. A common upgrade-time enhancement is a supported way to test code that depends on an element. For Blazor, `PlainKit.Blazor.Testing` is already that seam for `PkDataTable` (see the Blazor skill).

Before you file, search the existing issues, open and closed, for the same problem. If one exists, add a comment with your case and version instead of opening a duplicate; a closed one may be fixed in a newer version than you have.

Write it so a stranger can act on it: a generic, reusable title that names the element, component or export and not your app; the smallest repro you can make (a few lines, not your page); actual versus expected behaviour; and the affected Plainkit version. Leave out app-specific names, data, page paths and any other internal details. Give the type in the title or as a label (bug, enhancement or docs) so triage is quick.

Record the stopgap in the app next to the code that needs it, with the issue link, and remove it in the pull request that bumps Plainkit to the version containing the fix.
