<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mateusz Kornas</title>
    <description>The latest articles on DEV Community by Mateusz Kornas (@mkornas).</description>
    <link>https://dev.to/mkornas</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4098475%2F60d257dc-ddd0-4d08-9ad6-e78808343e78.jpg</url>
      <title>DEV Community: Mateusz Kornas</title>
      <link>https://dev.to/mkornas</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mkornas"/>
    <language>en</language>
    <item>
      <title>Moving from Angular Material to mk-kit, view by view</title>
      <dc:creator>Mateusz Kornas</dc:creator>
      <pubDate>Fri, 28 Aug 2026 07:23:08 +0000</pubDate>
      <link>https://dev.to/mkornas/moving-from-angular-material-to-mk-kit-view-by-view-4a22</link>
      <guid>https://dev.to/mkornas/moving-from-angular-material-to-mk-kit-view-by-view-4a22</guid>
      <description>&lt;p&gt;Angular Material is excellent at what it is: Google's design language, implemented carefully, maintained by the Angular team. If your product &lt;em&gt;should&lt;/em&gt; look like Material, stay. This post is for the other case — an admin panel or internal tool where Material was the default, not the decision, and where you keep writing the same things around it: a table with sorting and paging that does not need &lt;code&gt;MatTableDataSource&lt;/code&gt;, charts, a kanban board, a chat pane, a proper date-range picker, file upload, a rich-text field.&lt;/p&gt;

&lt;p&gt;mk-kit covers that surface in one package, and the migration is incremental: both libraries install side by side, selectors and tokens never collide, and you move view by view.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why teams switch
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Admin surface, not a design language.&lt;/strong&gt; 180 components including tables with tree rows and CSV export, twelve SVG chart types, kanban, chat, rich-text and block editors, query builder, file upload, signature pad, on-screen keyboard, dynamic forms from JSON.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Theming is CSS variables.&lt;/strong&gt; No &lt;code&gt;mat.theme()&lt;/code&gt; Sass, no palette maps, no &lt;code&gt;.mat-mdc-*&lt;/code&gt; overrides. Set &lt;code&gt;--mk-primary&lt;/code&gt;, get a consistent light and dark theme across everything, globally or per subtree, at runtime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Written for Angular 22.&lt;/strong&gt; Signal inputs everywhere, standalone, OnPush, zoneless, &lt;code&gt;resource()&lt;/code&gt;-friendly services, harness-tested. No zone.js assumptions, no &lt;code&gt;ngModule&lt;/code&gt; shims.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MIT, no strings.&lt;/strong&gt; No community edition, no runtime checks, nothing phones home.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The component map
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Angular Material&lt;/th&gt;
&lt;th&gt;mk-kit&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MatButton&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;button[mkButton]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;variant&lt;/code&gt; / &lt;code&gt;tone&lt;/code&gt; / &lt;code&gt;size&lt;/code&gt; / &lt;code&gt;iconOnly&lt;/code&gt; / &lt;code&gt;loading&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;MatIcon&lt;/code&gt; (ligatures)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;mk-icon name&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;provideMkMaterialIcons()&lt;/code&gt; keeps your names — see below&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MatDialog&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MkDialogService&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;open(Cmp, { data })&lt;/code&gt;, &lt;code&gt;MK_OVERLAY_DATA&lt;/code&gt;, &lt;code&gt;await ref.afterClosed&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;MatFormField&lt;/code&gt; + &lt;code&gt;MatInput&lt;/code&gt; + &lt;code&gt;MatError&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;mk-form-field&lt;/code&gt; + &lt;code&gt;input[mkInput]&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;label and hint are inputs; the error is derived from the bound control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;MatSelect&lt;/code&gt; / &lt;code&gt;MatAutocomplete&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;mk-select&lt;/code&gt; / &lt;code&gt;mk-autocomplete&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;[options]&lt;/code&gt; input instead of &lt;code&gt;&amp;lt;mat-option&amp;gt;&lt;/code&gt; children&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;MatTable&lt;/code&gt; + &lt;code&gt;MatSort&lt;/code&gt; + &lt;code&gt;MatPaginator&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;mk-table&lt;/code&gt; + &lt;code&gt;mkSort&lt;/code&gt; + &lt;code&gt;mk-pagination&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;plain arrays and signals instead of &lt;code&gt;MatTableDataSource&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MatSnackBar&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;MkSnackbarService&lt;/code&gt; / &lt;code&gt;MkToastService&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;bottom snackbar with action, or stacked toasts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;MatSlideToggle&lt;/code&gt; / &lt;code&gt;MatCheckbox&lt;/code&gt; / &lt;code&gt;MatRadio&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;mk-switch&lt;/code&gt; / &lt;code&gt;mk-checkbox&lt;/code&gt; / &lt;code&gt;mk-radio-group&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;same CVA bindings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;MatDatepicker&lt;/code&gt; / &lt;code&gt;MatTimepicker&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;mk-date-picker&lt;/code&gt; / &lt;code&gt;mk-time-picker&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;native &lt;code&gt;Date&lt;/code&gt;, no adapters; locale via &lt;code&gt;provideMkI18n&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;MatMenu&lt;/code&gt; / &lt;code&gt;MatTabs&lt;/code&gt; / &lt;code&gt;MatStepper&lt;/code&gt; / &lt;code&gt;MatChips&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;mk-menu&lt;/code&gt; / &lt;code&gt;mk-tabs&lt;/code&gt; / &lt;code&gt;mk-stepper&lt;/code&gt; / &lt;code&gt;mk-chip&lt;/code&gt;, &lt;code&gt;mk-tag-input&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;MatCard&lt;/code&gt; / &lt;code&gt;MatDivider&lt;/code&gt; / &lt;code&gt;MatList&lt;/code&gt; / &lt;code&gt;MatProgressBar&lt;/code&gt; / &lt;code&gt;MatSpinner&lt;/code&gt; / &lt;code&gt;MatTooltip&lt;/code&gt; / &lt;code&gt;MatBadge&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;mk-card&lt;/code&gt; / &lt;code&gt;mk-divider&lt;/code&gt; / &lt;code&gt;mk-list&lt;/code&gt; / &lt;code&gt;mk-progress-bar&lt;/code&gt; / &lt;code&gt;mk-spinner&lt;/code&gt; / &lt;code&gt;[mkTooltip]&lt;/code&gt; / &lt;code&gt;mk-badge&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;matBadge&lt;/code&gt; attribute → &lt;code&gt;mk-badge&lt;/code&gt; element&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;MatButtonToggle&lt;/code&gt; / &lt;code&gt;MatBottomSheet&lt;/code&gt; / &lt;code&gt;MatSidenav&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;mk-button-toggle-group&lt;/code&gt; / &lt;code&gt;MkBottomSheetService&lt;/code&gt; / &lt;code&gt;mk-app-shell&lt;/code&gt; + &lt;code&gt;mk-drawer&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CDK Overlay / DragDrop / Clipboard / A11y / VirtualScroll&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;MkOverlayService&lt;/code&gt;, &lt;code&gt;MkAnchoredPanel&lt;/code&gt; / &lt;code&gt;@mk-kit/ui/dnd&lt;/code&gt; / &lt;code&gt;mkCopyToClipboard&lt;/code&gt; / &lt;code&gt;MkFocusTrap&lt;/code&gt;, &lt;code&gt;MkLiveAnnouncer&lt;/code&gt; / &lt;code&gt;mk-virtual-scroll&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;keyboard drag built in&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Things you get that Material does not ship: charts, kanban, chat, rich text, block editor, query builder, file upload, cropper, gallery and lightbox, event calendar, tree, timeline, command palette, notification centre, guided tour, JSON viewer, diff, log viewer, QR code, dynamic forms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Icons: keep your Material names
&lt;/h2&gt;

&lt;p&gt;The built-in icon set is 426 SVG glyphs. &lt;code&gt;provideMkMaterialIcons()&lt;/code&gt; adds Material Symbols aliases (&lt;code&gt;delete&lt;/code&gt; → &lt;code&gt;trash&lt;/code&gt;, &lt;code&gt;expand_more&lt;/code&gt; → &lt;code&gt;chevron-down&lt;/code&gt;, &lt;code&gt;visibility_off&lt;/code&gt; → &lt;code&gt;eye-off&lt;/code&gt;, …), so ligature names survive a find-and-replace of the tag and the Symbols font download disappears:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- before --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;mat-icon&amp;gt;&lt;/span&gt;qr_code_scanner&lt;span class="nt"&gt;&amp;lt;/mat-icon&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- after --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;mk-icon&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"qr_code_scanner"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Errors and validation
&lt;/h2&gt;

&lt;p&gt;There is no &lt;code&gt;&amp;lt;mat-error&amp;gt;&lt;/code&gt; and no &lt;code&gt;ErrorStateMatcher&lt;/code&gt;. &lt;code&gt;mk-form-field&lt;/code&gt; reads the projected control's &lt;code&gt;NgControl&lt;/code&gt; and renders the first error itself, worded from the &lt;code&gt;validation&lt;/code&gt; i18n table — the per-field &lt;code&gt;@if&lt;/code&gt; ladder disappears. &lt;code&gt;errorOn="touched"&lt;/code&gt; reproduces Material's default timing; &lt;code&gt;errorMessages&lt;/code&gt; rewords a single key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;mk-form-field&lt;/span&gt; &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;"Email"&lt;/span&gt; &lt;span class="na"&gt;hint=&lt;/span&gt;&lt;span class="s"&gt;"Work address"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;mkInput&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;[formControl]=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/mk-form-field&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Constraint inputs behave like Material's validator directives: &lt;code&gt;[min]&lt;/code&gt; / &lt;code&gt;[max]&lt;/code&gt; on a date picker report &lt;code&gt;mkMinDate&lt;/code&gt; / &lt;code&gt;mkMaxDate&lt;/code&gt;, numeric controls report the standard &lt;code&gt;min&lt;/code&gt; / &lt;code&gt;max&lt;/code&gt; keys, and &lt;code&gt;required&lt;/code&gt; on &lt;code&gt;mk-checkbox&lt;/code&gt; behaves like &lt;code&gt;Validators.requiredTrue&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Theming
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;mat.theme()&lt;/code&gt; becomes custom properties. Import the stylesheet, set a handful of tokens, done:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--mk-primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#4f46e5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--mk-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--mk-font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;"Inter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;system-ui&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dark mode is built in via &lt;code&gt;data-mk-theme&lt;/code&gt; and &lt;code&gt;MkThemeService&lt;/code&gt;; the hand-rolled &lt;code&gt;body.dark&lt;/code&gt; token set gets deleted. Density is &lt;code&gt;data-mk-density="compact"&lt;/code&gt;. The &lt;a href="https://mk-kit.dev/theme-builder" rel="noopener noreferrer"&gt;theme builder&lt;/a&gt; generates the sheet from your brand colour.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest gaps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;No &lt;code&gt;MatTableDataSource&lt;/code&gt; — you own sort, filter and page with signals (usually less code), or use &lt;code&gt;MkTableDataSource&lt;/code&gt; for server-side paging.&lt;/li&gt;
&lt;li&gt;Select and autocomplete options are data inputs, not projected &lt;code&gt;&amp;lt;mat-option&amp;gt;&lt;/code&gt; templates.&lt;/li&gt;
&lt;li&gt;One field look — &lt;code&gt;appearance="outline"&lt;/code&gt; attributes just get deleted.&lt;/li&gt;
&lt;li&gt;Ripples are opt-in (&lt;code&gt;mkRipple&lt;/code&gt;); service APIs are Promise- and signal-based, not Observable-based.&lt;/li&gt;
&lt;li&gt;It does not look like Material. That is the point, but say it out loud to your designer first.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Suggested order
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Theme tokens.&lt;/li&gt;
&lt;li&gt;Icons (alias provider).&lt;/li&gt;
&lt;li&gt;Buttons, tooltips, spinners — the low-risk sweep that touches every screen.&lt;/li&gt;
&lt;li&gt;Form fields.&lt;/li&gt;
&lt;li&gt;Dialogs and bottom sheets.&lt;/li&gt;
&lt;li&gt;Tables.&lt;/li&gt;
&lt;li&gt;Pickers, chips, snackbars, menus.&lt;/li&gt;
&lt;li&gt;Drop &lt;code&gt;@angular/material&lt;/code&gt; and prune the &lt;code&gt;.mat-*&lt;/code&gt; override CSS.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The condensed map lives on the &lt;a href="https://mk-kit.dev/migration" rel="noopener noreferrer"&gt;migration page&lt;/a&gt;; the full guide with per-surface before/after snippets is &lt;code&gt;MIGRATION.md&lt;/code&gt; in the repository. Coming from PrimeNG instead? &lt;a href="https://mk-kit.dev/blog/switching-from-primeng" rel="noopener noreferrer"&gt;That post has a schematic.&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Stuck on a specific screen? &lt;a href="https://github.com/mk-kit/mk-kit/issues" rel="noopener noreferrer"&gt;Open an issue&lt;/a&gt; with the template — mapping questions get answered, and real gaps get built.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Switching from PrimeNG? Here's the MIT path.</title>
      <dc:creator>Mateusz Kornas</dc:creator>
      <pubDate>Fri, 28 Aug 2026 06:50:11 +0000</pubDate>
      <link>https://dev.to/mkornas/switching-from-primeng-heres-the-mit-path-3ohg</link>
      <guid>https://dev.to/mkornas/switching-from-primeng-heres-the-mit-path-3ohg</guid>
      <description>&lt;p&gt;PrimeNG has been the default answer to "which Angular component library?" for a decade. On 28 June 2026 that answer got a price tag. If you are one of the teams now doing the maths, this post is the map: what actually changed, what your options are, and — if you pick the MIT route — exactly how far a schematic gets you and where you still have to think.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed, in plain terms
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PrimeNG 22 and later ship under the PrimeUI licence&lt;/strong&gt;, not MIT. The same applies to PrimeVue 5+ and PrimeReact 11+. The GitHub repository moved to security-fixes-only the same day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PrimeNG 21 and everything before it stays MIT.&lt;/strong&gt; Nobody can take back a licence you already have.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The commercial licence is $599 per developer&lt;/strong&gt; (perpetual, with a year of updates) until the end of 2026 and &lt;strong&gt;$799 from 2027&lt;/strong&gt;, plus $399 per developer per year to keep receiving updates after that.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A free community licence exists&lt;/strong&gt;, but only if your company meets &lt;em&gt;all&lt;/em&gt; of: under $1M revenue, fewer than 5 developers, fewer than 10 employees, under $3M outside funding. It is renewed yearly and checked at runtime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The parts most admin apps lean on hardest are sold separately&lt;/strong&gt; as PrimeUI PRO: Scheduler ($799), Text Editor ($499), Charts ($399), Task Board ($399). A data grid, spreadsheet, gantt and diagram are announced for later in 2026.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this is a criticism. Maintaining 90+ components for free for ten years is a gift, and a company is allowed to stop giving it. But it does change your plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your four options
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Freeze on PrimeNG 21.&lt;/strong&gt; It is MIT and it works. It will not follow Angular past the versions it supports, so you are buying time, not a solution. Fine for an app in maintenance mode.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pay.&lt;/strong&gt; For a 20-developer team that is $12k now, $16k from January, and ~$8k a year after that to stay current — before any PRO widgets. Entirely reasonable if PrimeNG is deeply woven into a product that makes money.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Move to the community fork.&lt;/strong&gt; &lt;a href="https://github.com/openng-org/optimus-ui" rel="noopener noreferrer"&gt;Optimus UI&lt;/a&gt; by the OpenNG Foundation keeps the selectors and class names identical, so it is the least disruptive move. It also inherits PrimeNG's open issues and is run by volunteers. Worth a look if you need zero template changes today.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Migrate to a library that was MIT from the start and says so in writing.&lt;/strong&gt; This is the mk-kit route, and the rest of this post is about it.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What mk-kit is (and is not)
&lt;/h2&gt;

&lt;p&gt;mk-kit is an Angular 22 component library built for admin panels and internal tools: &lt;strong&gt;180 components, MIT, no runtime licence checks, no revenue thresholds, no community edition.&lt;/strong&gt; Every input is a signal, every component is standalone and OnPush, it runs zoneless, it is WCAG 2.1 AA, and the whole theme is &lt;code&gt;--mk-*&lt;/code&gt; CSS custom properties with light and dark out of the box.&lt;/p&gt;

&lt;p&gt;It is deliberately narrower than PrimeNG. There is no PDF viewer, no spreadsheet, no diagram editor, no terminal, no dock. There &lt;em&gt;is&lt;/em&gt; everything an admin app needs — and the categories PrimeUI sells as PRO are in the free package:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;PrimeNG&lt;/th&gt;
&lt;th&gt;mk-kit&lt;/th&gt;
&lt;th&gt;Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;p-table&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mk-table&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;MkTableDataSource&lt;/code&gt;, tree rows, CSV export, print&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;p-select&lt;/code&gt; / &lt;code&gt;p-dropdown&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mk-select&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;[options]&lt;/code&gt; of &lt;code&gt;{ label, value }&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;p-multiSelect&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mk-multi-select&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;p-datePicker&lt;/code&gt; / &lt;code&gt;p-calendar&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mk-date-picker&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;plus range, time, datetime, month, week pickers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;p-dialog&lt;/code&gt; / &lt;code&gt;DialogService&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MkDialogService&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;confirm()&lt;/code&gt; and &lt;code&gt;prompt()&lt;/code&gt; built in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;p-toast&lt;/code&gt; / &lt;code&gt;MessageService&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MkToastService&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;toast.success(detail, { title })&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;p-menu&lt;/code&gt; / &lt;code&gt;p-contextMenu&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;mk-menu&lt;/code&gt; / &lt;code&gt;mkContextMenuTriggerFor&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;nested submenus&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;p-chart&lt;/code&gt; &lt;strong&gt;(PRO)&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;mk-line-chart&lt;/code&gt;, &lt;code&gt;mk-bar-chart&lt;/code&gt;, &lt;code&gt;mk-donut-chart&lt;/code&gt;, …&lt;/td&gt;
&lt;td&gt;SVG, themed by tokens, no Chart.js&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;p-editor&lt;/code&gt; &lt;strong&gt;(PRO)&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;mk-rich-text&lt;/code&gt; / &lt;code&gt;mk-block-editor&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scheduler &lt;strong&gt;(PRO)&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mk-event-calendar&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;resource timeline lives in &lt;a href="https://mk-kit.dev/pro" rel="noopener noreferrer"&gt;Pro&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Task Board &lt;strong&gt;(PRO)&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mk-kanban&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;p-cascadeSelect&lt;/code&gt; / &lt;code&gt;p-listbox&lt;/code&gt; / &lt;code&gt;p-treeSelect&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;mk-cascader&lt;/code&gt; / &lt;code&gt;mk-listbox&lt;/code&gt; / &lt;code&gt;mk-tree-select&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;p-fileUpload&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mk-file-upload&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;p-blockUI&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mkBlockUi&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;p-picklist&lt;/code&gt; / &lt;code&gt;p-orderlist&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;mk-transfer-list&lt;/code&gt; / &lt;code&gt;mk-sortable-list&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;a href="https://mk-kit.dev/components-index" rel="noopener noreferrer"&gt;full component index&lt;/a&gt; has all 180; the &lt;a href="https://mk-kit.dev/api" rel="noopener noreferrer"&gt;API reference&lt;/a&gt; is generated from the source, and there is an &lt;code&gt;llms.txt&lt;/code&gt; if you would rather ask your editor.&lt;/p&gt;

&lt;h2&gt;
  
  
  The schematic does the boring part
&lt;/h2&gt;

&lt;p&gt;Install mk-kit next to PrimeNG (both can live in one app — the selectors and CSS never collide) and run the migration in report mode first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng add @mk-kit/ui
ng g @mk-kit/ui:migrate-primeng &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You get a &lt;code&gt;primeng-migration.md&lt;/code&gt; report before anything is touched. Then apply it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng g @mk-kit/ui:migrate-primeng
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What it rewrites for you&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;primeng/*&lt;/code&gt; imports and class names → &lt;code&gt;@mk-kit/ui&lt;/code&gt; (&lt;code&gt;ButtonModule&lt;/code&gt; → &lt;code&gt;MkButton&lt;/code&gt;, &lt;code&gt;MessageService&lt;/code&gt; → &lt;code&gt;MkToastService&lt;/code&gt;, …), deduping the &lt;code&gt;imports: []&lt;/code&gt; arrays.&lt;/li&gt;
&lt;li&gt;Selectors that map 1:1, in &lt;code&gt;.html&lt;/code&gt; files &lt;em&gt;and&lt;/em&gt; inline templates: &lt;code&gt;pButton&lt;/code&gt; → &lt;code&gt;mkButton&lt;/code&gt;, &lt;code&gt;pInputText&lt;/code&gt; → &lt;code&gt;mkInput&lt;/code&gt;, &lt;code&gt;p-select&lt;/code&gt; → &lt;code&gt;mk-select&lt;/code&gt;, &lt;code&gt;p-checkbox&lt;/code&gt;, &lt;code&gt;p-toggleswitch&lt;/code&gt;, &lt;code&gt;p-table&lt;/code&gt;, &lt;code&gt;p-tabView&lt;/code&gt;, &lt;code&gt;p-accordion&lt;/code&gt;, &lt;code&gt;p-tag&lt;/code&gt;, &lt;code&gt;p-chip&lt;/code&gt;, &lt;code&gt;p-avatar&lt;/code&gt;, &lt;code&gt;p-skeleton&lt;/code&gt;, &lt;code&gt;p-drawer&lt;/code&gt;, &lt;code&gt;pTooltip&lt;/code&gt; → &lt;code&gt;mkTooltip&lt;/code&gt; — about 150 rules in total.&lt;/li&gt;
&lt;li&gt;Mechanical inputs: &lt;code&gt;[value]&lt;/code&gt; → &lt;code&gt;[data]&lt;/code&gt; on tables, &lt;code&gt;severity&lt;/code&gt; → &lt;code&gt;tone&lt;/code&gt;, &lt;code&gt;[(activeIndex)]&lt;/code&gt; → &lt;code&gt;[(selectedIndex)]&lt;/code&gt;, &lt;code&gt;[(visible)]&lt;/code&gt; → &lt;code&gt;[(open)]&lt;/code&gt; on drawers, &lt;code&gt;tooltipPosition&lt;/code&gt; → &lt;code&gt;mkTooltipPlacement&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;angular.json&lt;/code&gt; styles (PrimeNG theme and primeicons out, the mk-kit stylesheet in) and &lt;code&gt;package.json&lt;/code&gt; (the PrimeNG packages are removed once nothing unmapped is left).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What it leaves a note for&lt;/strong&gt; — a &lt;code&gt;&amp;lt;!-- mk-kit: … --&amp;gt;&lt;/code&gt; comment in the template plus a line in the report with a docs link:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;p-dialog [(visible)]&lt;/code&gt; → &lt;code&gt;MkDialogService.open(Component)&lt;/code&gt;; &lt;code&gt;p-confirmDialog&lt;/code&gt; → &lt;code&gt;await dialog.confirm(…)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;p-toast&lt;/code&gt; host and &lt;code&gt;MessageService.add({ severity, summary, detail })&lt;/code&gt; → &lt;code&gt;toast.success(detail, { title })&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Menus, breadcrumbs and steppers driven by &lt;code&gt;[model]&lt;/code&gt; → child elements; &lt;code&gt;p-chart&lt;/code&gt; → the matching SVG chart; &lt;code&gt;pTemplate&lt;/code&gt; → content slots.&lt;/li&gt;
&lt;li&gt;Anything with no counterpart — it is listed, not guessed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rule is simple: &lt;strong&gt;the schematic never rewrites something it cannot make compile.&lt;/strong&gt; Handle the notes and the build goes green.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest gaps
&lt;/h2&gt;

&lt;p&gt;You should know these before you start, not halfway through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No organisation chart, dock, terminal, meter group or float-label variant. The first is on the roadmap; the others are not planned.&lt;/li&gt;
&lt;li&gt;No PDF viewer, spreadsheet or diagram editor — each is a product on its own, and PrimeUI sells them separately too.&lt;/li&gt;
&lt;li&gt;Options for selects are data (&lt;code&gt;[options]&lt;/code&gt;), not projected option elements. The schematic converts the common &lt;code&gt;{ label, value }&lt;/code&gt; shape; custom option templates move to the component's option template slot.&lt;/li&gt;
&lt;li&gt;Services are Promise- and signal-based, not Observable-based. &lt;code&gt;await dialog.confirm()&lt;/code&gt; instead of &lt;code&gt;.subscribe()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your report lists something that is not in this list, &lt;a href="https://github.com/mk-kit/mk-kit/issues" rel="noopener noreferrer"&gt;open an issue&lt;/a&gt; with the report attached. I read every one, and gaps that block a migration go to the top of the queue.&lt;/p&gt;

&lt;h2&gt;
  
  
  A sane order of work
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Run the dry run. Read the report. Count the notes — that is your real effort.&lt;/li&gt;
&lt;li&gt;Swap the theme: delete the PrimeNG theme and &lt;code&gt;primeicons&lt;/code&gt;, set &lt;code&gt;--mk-primary&lt;/code&gt; and friends (the &lt;a href="https://mk-kit.dev/theme-builder" rel="noopener noreferrer"&gt;theme builder&lt;/a&gt; writes the file).&lt;/li&gt;
&lt;li&gt;Apply the schematic. Fix the notes, one screen at a time, with both libraries installed.&lt;/li&gt;
&lt;li&gt;Drop &lt;code&gt;primeng&lt;/code&gt; from &lt;code&gt;package.json&lt;/code&gt; when the report is empty.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The notes cluster around dialogs, toasts and menus — once you have converted one of each, the rest is repetition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Timing
&lt;/h2&gt;

&lt;p&gt;The price step to $799 happens on 1 January 2027, and PrimeNG 21 will not follow Angular forever. If you are going to move, the cheapest moment is while PrimeNG 21 still builds cleanly against your Angular version and both libraries can coexist.&lt;/p&gt;

&lt;p&gt;And if you are not going to move — genuinely, that is fine. Pay the people who built the thing you use. Just make it a decision rather than a default.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Want a second pair of eyes on your report? Attach it to an issue, or say hello via the &lt;a href="https://mk-kit.dev/pro" rel="noopener noreferrer"&gt;Pro waitlist form&lt;/a&gt; if you would like the resource scheduler, gantt and the rest of the paid widgets on the same theme.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
