ngx-pk-ui 3.0.0

June 21, 2026 · View on GitHub

An Angular 22 component library providing UI components and CSS utilities.

  • Angular: ^22.0.0
  • Standalone components · Signals · Vitest
  • License: MIT

Changelog

See CHANGELOG.md for full version history.

Angular Version Compatibility

ngx-pk-ui versionAngular versionNotes
v3.x22Fully supported
v2.x21Fully supported
v2.x20Likely works (use --legacy-peer-deps)
v2.x19Mostly works
v2.x17–18Partial support

Demo & Usage

Example Pages

PageRouteDescription
Login/examples/loginFull-bleed login card with form validation and password strength meter
Chat App/examples/chatIcon sidenav, conversation list, and message pane
Dashboard/examples/dashboardpk-sidenav + inline topbar + stat cards + content cards

npm public

Installation

npm install ngx-pk-ui

Components

ComponentTypeDescription
pk-accordionComponentCollapsible panels with single / multi-open mode
pk-tabsComponentTab container with content projection
pk-toastrComponent + ServiceToast notifications
pk-alertComponent + ServiceModal alert / confirm / input dialogs
pk-modalComponentFlexible modal overlay with slot components, size and theme
pk-iconComponentSVG icon set + Material Symbols mode
pk-datagridModule + ComponentsDatagrid with sort, filter, resize, pagination, row detail, row selection
pk-datepickerComponentDatepicker with PkLocale support, range, and clear action
pk-progressComponentLine/circle progress with status variants
pk-treeviewModule + ComponentsHierarchical tree with expand/collapse and selection modes
pk-selectComponentSingle/multi select with optional search
pk-autocompleteComponentLocal/async autocomplete input
pk-sidenavComponentLeft/right side navigation — full/icon/auto mode, multi-level, 4 themes, CSS-variable override
pk-tooltipDirectiveHover tooltip — 10 color variants, 4 positions
pk-calendarComponentYear/Month/Week/Day/Agenda views, drag & drop, TH/EN locale
pk-file-uploadComponentDrag & drop file upload with browser-native preview (image/PDF/text)
pk-heatmapComponentGitHub-style contribution heatmap — 4 color schemes, 17-locale labels, legend
pk-markdown-viewerComponentStandalone Markdown renderer — Print/Export toolbar, light/dark theme
pk-timelineComponentVertical/horizontal timeline with icons, images, and active state
pk-splitComponentResizable split pane — drag divider to resize panels, horizontal or vertical
pk-barcodeComponentInline SVG barcode — Code 128, Code 39, EAN-13, EAN-8; download PNG/SVG
pk-qrcodeComponentInline SVG QR code — versions 1–40, EC levels L/M/Q/H, center logo, download PNG/SVG
pk-code-readerComponentQR code & barcode scanner — native BarcodeDetector API, camera / upload / paste, overlay, beep, torch, camera switch
pk-radio-groupComponentCustom-styled radio button group — ControlValueAccessor, vertical/horizontal layout, per-option disabled
pk-timepickerComponentTime picker — spinner / number / dropdown input styles, 24H/12H, ControlValueAccessor, format hms/hm/h
pk-context-menuDirective + ServiceRight-click context menu — [pkContextMenu] directive, 7 themes, vertical/horizontal layout, keyboard navigation, auto-position

pk-accordion

import { PkAccordion, PkAccordionItem } from 'ngx-pk-ui';

@Component({
  imports: [PkAccordion, PkAccordionItem],
})
<!-- Single-open (default) -->
<pk-accordion>
  <pk-accordion-item label="Section 1">Content goes here.</pk-accordion-item>
  <pk-accordion-item label="Section 2" [open]="true">Starts expanded.</pk-accordion-item>
  <pk-accordion-item label="Disabled" [disabled]="true">Cannot open.</pk-accordion-item>
</pk-accordion>

<!-- Multi-open -->
<pk-accordion [multi]="true">
  <pk-accordion-item label="A">...</pk-accordion-item>
  <pk-accordion-item label="B">...</pk-accordion-item>
</pk-accordion>
InputComponentTypeDefaultDescription
multiPkAccordionbooleanfalseAllow multiple panels open simultaneously
labelPkAccordionItemstringrequiredPanel header text
openPkAccordionItembooleanfalseExpand on init
disabledPkAccordionItembooleanfalsePrevent toggling

pk-split

import { PkSplit, PkSplitPanel } from 'ngx-pk-ui';

@Component({
  imports: [PkSplit, PkSplitPanel],
})
<!-- Horizontal — left / right (default) -->
<pk-split style="height: 400px">
  <pk-split-panel><p>Left panel</p></pk-split-panel>
  <pk-split-panel><p>Right panel</p></pk-split-panel>
</pk-split>

<!-- Vertical — top / bottom -->
<pk-split direction="vertical" style="height: 400px">
  <pk-split-panel><p>Top panel</p></pk-split-panel>
  <pk-split-panel><p>Bottom panel</p></pk-split-panel>
</pk-split>

<!-- Custom sizes -->
<pk-split [initialSize]="30" [minSize]="15" [gutterSize]="8" (sizeChange)="onResize($event)">
  <pk-split-panel>...</pk-split-panel>
  <pk-split-panel>...</pk-split-panel>
</pk-split>
Input/OutputTypeDefaultDescription
direction'horizontal'|'vertical''horizontal'Layout direction — left/right or top/bottom
initialSizenumber50Starting size of first panel (%)
minSizenumber10Minimum size of either panel (%)
gutterSizenumber6Divider thickness (px)
(sizeChange)[number, number]Emits [sizeA%, sizeB%] on every drag

pk-timepicker

import { PkTimepicker } from 'ngx-pk-ui';
import type { PkTimeFormat, PkTimeType, PkTimeInputType } from 'ngx-pk-ui';

@Component({
  imports: [PkTimepicker, FormsModule],
})
<!-- Basic (24H, hm, inputs) -->
<pk-timepicker [(ngModel)]="time" />

<!-- 12H mode, hms format, number spinner -->
<pk-timepicker [(ngModel)]="time" type="12H" format="hms" inputType="spinner" />

<!-- Dropdown mode, custom height -->
<pk-timepicker [(ngModel)]="time" inputType="dropdown" [customStyle]="{ height: '42px' }" />
Input/OutputTypeDefaultDescription
format'hms'|'hm'|'h''hm'Fields shown
type'24H'|'12H''24H'Clock mode — 12H shows AM/PM toggle
inputType'spinner'|'number'|'dropdown''number'UI style
customClassstring''Extra CSS class on container
customStyleRecord<string,string>{}Inline styles (e.g. override height)
(onTimeChange)stringEmits 24H time string on every change

Value is always a 24H string"14:30", "14:30:05", or "14". Default height 35px.


CSS Utilities

FileDescription
pk-grid.cssResponsive 12-column grid
pk-btn.cssButton variants and groups
pk-spinner.cssLoading spinners
pk-badge.cssBadges and dot indicators
pk-card.cssCard layouts
pk-table.cssStyled tables with striped, hover, bordered, size and color variants
pk-toggle.cssToggle switch replacing <input type="checkbox">
pk-form.cssFloating label fields for input, select, textarea — prefix/suffix, counter, group layout
pk-layout.cssFixed top navbar + sidebar layout shell — all CSS variables, responsive
pk-font.cssThai & Lao Google Fonts helper classes (opt-in, not in pk-ui.css)
pk-icon-font.cssMaterial Symbols font classes

Include all at once

// angular.json
"styles": ["node_modules/ngx-pk-ui/styles/pk-ui.css"]

Or import individually:

@import 'ngx-pk-ui/styles/pk-btn.css';
@import 'ngx-pk-ui/styles/pk-grid.css';
@import 'ngx-pk-ui/styles/pk-table.css';

pk-table

<!-- Basic -->
<table class="pk-table">
  <thead><tr><th>Name</th><th>Status</th></tr></thead>
  <tbody><tr><td>Alice</td><td>Active</td></tr></tbody>
</table>

<!-- Striped + hover + colored header -->
<table class="pk-table pk-table-primary pk-table-striped pk-table-hover">...</table>

<!-- Responsive wrapper -->
<div class="pk-table-responsive">
  <table class="pk-table pk-table-bordered">...</table>
</div>
ClassDescription
pk-tableBase styles (required)
pk-table-stripedAlternating row background
pk-table-hoverRow highlight on hover
pk-table-borderedBorder on every cell
pk-table-smReduced padding
pk-table-compactMinimal padding + smaller font
pk-table-primary/success/warn/errorColored <thead>
pk-table-responsiveWrapper <div> — horizontal scroll on overflow

pk-toggle

<!-- Minimal -->
<label class="pk-toggle">
  <input type="checkbox" />
  <span class="pk-toggle__track"></span>
</label>

<!-- With label + color variant -->
<label class="pk-toggle pk-toggle-success">
  <input type="checkbox" checked />
  <span class="pk-toggle__track"></span>
  <span class="pk-toggle__label">Enable feature</span>
</label>

<!-- Angular two-way binding -->
<label class="pk-toggle">
  <input type="checkbox" [(ngModel)]="isEnabled" />
  <span class="pk-toggle__track"></span>
  <span class="pk-toggle__label">{{ isEnabled ? 'On' : 'Off' }}</span>
</label>
ClassDescription
pk-toggleWrapper <label> — required
pk-toggle__trackTrack + thumb <span> — required
pk-toggle__labelOptional text label <span>
pk-toggle-success/warn/errorChecked color variant
`pk-toggle-sm$\text{Small} (34 \times 18 \text{px})
pktogglelgpk-toggle-lg\text{Large} (56 \times 30 \text{px})
$pk-toggle-label-left`Move label to the left of the track

pk-form

Floating label form fields — pure CSS, works with input, select, and textarea. The input must have placeholder=" " (single space) for the float animation to work.

<!-- Basic input -->
<div class="pk-field">
  <input class="pk-field__input" type="text" placeholder=" " id="name" />
  <label class="pk-field__label" for="name">Full name</label>
</div>

<!-- Prefix / Suffix -->
<div class="pk-field">
  <div class="pk-field__wrap">
    <span class="pk-field__prefix">@</span>
    <input class="pk-field__input" type="text" placeholder=" " id="user" />
    <span class="pk-field__suffix">.com</span>
  </div>
  <label class="pk-field__label" for="user">Username</label>
</div>

<!-- Error state with message -->
<div class="pk-field pk-field--error">
  <input class="pk-field__input" type="email" placeholder=" " id="email" />
  <label class="pk-field__label" for="email">Email</label>
  <span class="pk-field__error">Invalid email address</span>
</div>

<!-- Form group (2-column) -->
<div class="pk-form-group pk-form-group--2">
  <div class="pk-field"> ... </div>
  <div class="pk-field"> ... </div>
</div>

Wrapper modifier classes:

ClassDescription
pk-fieldRequired wrapper
pk-field--filledFilled background, bottom border only (Material style)
pk-field--underlineNo border box, underline only
pk-field--pillFully rounded corners
pk-field--outlinedAdds glow ring on focus
pk-field--smSmall (42 px height)
pk-field--lgLarge (60 px height)
pk-field--successGreen border + label
pk-field--errorRed border + label

Element classes:

ClassElementDescription
pk-field__inputinput / select / textareaForm control — must have placeholder=" "
pk-field__labellabelFloating label — must come after the input in the DOM
pk-field__wrapdivFlex row container for prefix/suffix + input
pk-field__prefixspanLeft-attached addon
pk-field__suffixspanRight-attached addon
pk-field__hintspanHelper text (grey)
pk-field__errorspanError message (red)
pk-field__footerdivFlex row: hint left + counter right
pk-field__counterspanCharacter counter (right-aligned)

Layout helpers:

ClassDescription
pk-form-groupResponsive flex row of fields
pk-form-group--22-column layout
pk-form-group--33-column layout
pk-form-sectionSection divider label (uppercase, border-bottom)

pk-font

pk-font.css is opt-in — it is NOT included in pk-ui.css. Import separately:

// angular.json
"styles": [
  "node_modules/ngx-pk-ui/styles/pk-ui.css",
  "node_modules/ngx-pk-ui/styles/pk-font.css"
]
<p class="pk-font-sarabun">สวัสดี</p>
<p class="pk-font-kanit">สวัสดี</p>
<p class="pk-font-phetsarath">ສະບາຍດີ</p>
ClassFontScript
pk-font-bai-jamjureeBai JamjureeThai
pk-font-chakra-petchChakra PetchThai
pk-font-charmCharmThai
pk-font-charmonmanCharmonmanThai
pk-font-kanitKanitThai
pk-font-mitrMitrThai
pk-font-noto-sans-thaiNoto Sans ThaiThai
pk-font-pattayaPattayaThai
pk-font-promptPromptThai
pk-font-sarabunSarabunThai
pk-font-srirachaSrirachaThai
pk-font-srisakdiSrisakdiThai
pk-font-thasadithThasadithThai
pk-font-trirongTrirongThai
pk-font-noto-sans-laoNoto Sans LaoLao
pk-font-noto-sans-lao-loopedNoto Sans Lao LoopedLao
pk-font-noto-serif-laoNoto Serif LaoLao
pk-font-phetsarathPhetsarathLao

Note: Google Sans is proprietary (not on Google Fonts CDN) and is excluded.


Development

# Build the library
ng build ngx-pk-ui

# Run all tests (Vitest, headless)
ng test ngx-pk-ui --no-watch

# Run one spec file
npx vitest run projects/ngx-pk-ui/src/lib/pk-tabs/pk-tabs.spec.ts

# Serve the example app
npm run start:example

# Publish to npm (after build)
npm publish dist/ngx-pk-ui

Credits

Developed with the assistance of GitHub Copilot.