npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@keepui/ui

v0.6.4

Published

KeepUI — Angular cross-platform UI component library with optional Capacitor support

Readme

KeepUI

Component library for Angular with multi-platform support (web and Angular + Capacitor). Built on Tailwind CSS v4 with full light/dark theming and i18n via @jsverse/transloco.

Auto-generated from JSDoc in the source files. Do not edit manually — run npm run docs:generate to update.


1. Package identity

| Field | Value | |---|---| | Package name | @keepui/ui | | Angular compat | >= 21 | | Style engine | Tailwind CSS v4 | | i18n engine | @jsverse/transloco |


2. Installation

Option A — local build (development)

npm run build         # outputs to dist/keep-ui
npm install /absolute/path/to/dist/keep-ui

Option B — npm registry

npm install @keepui/ui

Required peer dependencies

npm install @angular/common @angular/core @jsverse/transloco

3. Global styles (required)

Add once to the host application's global stylesheet (e.g. src/styles.css):

@import "@keepui/ui/styles";

Provides:

  • Light theme CSS custom properties (default)
  • Dark theme via [data-theme="dark"]
  • Auto dark via @media (prefers-color-scheme: dark)
  • Tailwind v4 @theme inline mappings for all bg-keepui-*, text-keepui-*, border-keepui-*, shadow-keepui-* utilities

Theme switching at runtime

document.documentElement.setAttribute('data-theme', 'dark');   // force dark
document.documentElement.setAttribute('data-theme', 'light');  // force light
document.documentElement.removeAttribute('data-theme');         // follow OS

4. Provider setup (app.config.ts)

Web application

import { provideKeepUi, provideKeepUiI18n } from '@keepui/ui';

export const appConfig: ApplicationConfig = {
  providers: [
    provideKeepUi(),              // registers WebFileService for FILE_PORT
    provideKeepUiI18n(),          // default language: 'en'
    // provideKeepUiI18n({ defaultLang: 'es' }),
  ],
};

Angular + Capacitor application

import { provideKeepUiCapacitor } from '@keepui/ui/capacitor';
import { provideKeepUiI18n } from '@keepui/ui';

export const appConfig: ApplicationConfig = {
  providers: [provideKeepUiCapacitor(), provideKeepUiI18n()],
};

Rule: Never register both provideKeepUi() and provideKeepUiCapacitor() at the same time.

Available provider functions

provideKeepUiI18n(options?: KeepUiI18nOptions = {}): EnvironmentProviders

Registers all providers required for KeepUI internationalisation.

  • Configures a self-contained Transloco instance scoped to 'keepui'.
  • Bundles all translations inline — no HTTP assets required.
  • Provides {@link KeepUiLanguageService} so the host app can switch locale.

Usage in app.config.ts

export const appConfig: ApplicationConfig = {
  providers: [
    provideKeepUi(),
    provideKeepUiI18n(),                // default language: 'en'
    provideKeepUiI18n({ defaultLang: 'es' }), // or start in Spanish
  ],
};

Changing language at runtime

const lang = inject(KeepUiLanguageService);
lang.setLanguage('de');

Note: If your application already calls provideTransloco(), do NOT call provideKeepUiI18n() — instead configure your Transloco loader to handle the 'keepui/{lang}' scope paths, and provide KeepUiLanguageService manually.

provideKeepUi(): EnvironmentProviders

Registers KeepUI core providers for a web Angular application.

Registers WebFileService as the implementation of FILE_PORT, enabling all KeepUI components to use the browser's native file picker.

Add to app.config.ts:

export const appConfig: ApplicationConfig = {
  providers: [provideKeepUi()],
};

5. Component API reference

All components are standalone. Import directly from @keepui/ui.

5.1 ButtonComponent

Selector: keepui-button Import: import { ButtonComponent } from '@keepui/ui';

Accessible, themed action button with support for variants, shapes, sizes, loading state, full-width layout, and named icon slots.

Works identically on web and Angular + Capacitor (no native API usage).

<!-- Basic usage -->
<keepui-button (clicked)="save()">Save</keepui-button>

<!-- Primary, pill-shaped, fixed width -->
<keepui-button variant="primary" shape="pill">Confirm</keepui-button>

<!-- With leading icon (any inline element) -->
<keepui-button variant="outline" size="auto">
  <svg slot="leading" width="16" height="16" aria-hidden="true">…</svg>
  Upload
</keepui-button>

<!-- Loading state -->
<keepui-button [loading]="isSaving()">Saving…</keepui-button>

<!-- Full-width, danger -->
<keepui-button variant="danger" [fullWidth]="true">Delete account</keepui-button>

<!-- Icon-only (requires ariaLabel for accessibility) -->
<keepui-button variant="ghost" size="auto" ariaLabel="Close dialog">
  <svg slot="leading" …>…</svg>
</keepui-button>

Inputs

| Input | Type | Default | Description | |---|---|---|---| | variant | ButtonVariant | 'primary' | Visual style of the button. | | size | ButtonSize | 'md' | Size mode.

  • md → fixed 160 px wide, 40 px tall.
  • auto → padding-driven width, 40 px tall. | | shape | ButtonShape | 'pill' | Border-radius style. | | type | ButtonType | 'button' | HTML type attribute of the inner <button>. | | disabled | boolean | false | Disables the button when true. | | loading | boolean | false | Replaces the content with an animated spinner and sets aria-busy. Also disables the button until the operation completes. | | fullWidth | boolean | false | Expands the button to fill its container width. | | ariaLabel | string | '' | Accessible label for icon-only buttons. When provided, sets the aria-label attribute on the inner <button>. |

Outputs

| Output | Emitter type | Description | |---|---|---| | clicked | OutputEmitterRef<void> | Emitted when the button is clicked and is not disabled or loading. |

Content slots (ng-content)

| Slot | Description | |---|---| | (default) | Main projected content | | [slot='leading'] | Leading icon/element. Hidden while loading. | | [slot='trailing'] | Trailing icon/element. Hidden while loading. |


5.2 CardComponent

Selector: keepui-card Import: import { CardComponent } from '@keepui/ui';

Contenedor versátil con soporte de variante, padding, color, estado clickable, seleccionado y scrollable.

padding="screen" aplica padding lateral y superior pero omite el inferior intencionadamente para que el contenido parezca continuar más allá del área visible, invitando al usuario a hacer scroll. Un div espaciador se inserta automáticamente al final del contenido proyectado: cuando el usuario llega al fondo, el espaciador reproduce el padding inferior correcto sin que el consumidor deba declararlo.

<keepui-card>Contenido</keepui-card>

<keepui-card variant="flat" padding="lg" [clickable]="true" (clicked)="onSelect()">
  Card clicable
</keepui-card>

<div class="h-screen overflow-hidden">
  <keepui-card padding="screen" [scrollable]="true" [fullHeight]="true">
    Contenido largo — el padding inferior se gestiona automáticamente
  </keepui-card>
</div>

Inputs

| Input | Type | Default | Description | |---|---|---|---| | variant | CardVariant | 'outlined' | | | padding | CardPadding | 'md' | | | colors | CardColors | 'primary' | | | clickable | boolean | false | | | selected | boolean | false | | | scrollable | boolean | false | | | fullHeight | boolean | false | |

Outputs

| Output | Emitter type | Description | |---|---|---| | clicked | OutputEmitterRef<void> | |


5.3 IconActionButtonComponent

Selector: keepui-icon-action-button Import: import { IconActionButtonComponent } from '@keepui/ui';

Circular icon-only action button with default and danger variants, loading state, and full accessibility support.

Because this button renders no visible text, ariaLabel is required to satisfy WCAG 2.1 SC 4.1.2 (Name, Role, Value).

The icon color is inherited automatically via currentColor from the button's text color, so SVG symbols defined with stroke="currentColor" will adapt to both variants and themes without extra classes.

<keepui-icon-action-button icon="edit-icon" ariaLabel="Editar" />

<keepui-icon-action-button
  icon="trash-icon"
  variant="danger"
  ariaLabel="Eliminar elemento"
  [loading]="isDeleting()"
/>

Inputs

| Input | Type | Default | Description | |---|---|---|---| | icon | unknown | — | ID of the SVG symbol to render (without the # prefix). | | ariaLabel | unknown | — | Accessible label for the button. Always required — icon-only buttons must have a programmatic name for screen readers (WCAG 2.1 SC 4.1.2). | | variant | IconActionButtonVariant | 'default' | Visual style variant. | | iconSize | number | 20 | Size of the inner icon in pixels. | | type | IconActionButtonType | 'button' | HTML type attribute of the inner <button>. | | disabled | boolean | false | Disables the button when true. | | loading | boolean | false | Shows an animated spinner and disables the button. Also sets aria-busy="true" on the element. |


5.4 IconComponent

Selector: keepui-icon Import: import { IconComponent } from '@keepui/ui';

Generic SVG sprite icon renderer.

Renders a <use href="#name"> reference pointing to an SVG symbol pre-registered in the DOM by the consuming application (e.g. via IconRegistryService).

Accessibility:

  • When used decoratively (default), the SVG carries aria-hidden="true" automatically.
  • When used as a standalone meaningful icon, supply an ariaLabel — the SVG will receive role="img" and aria-label accordingly.
<!-- Decorative — hidden from screen readers -->
<keepui-icon name="check-icon" [size]="20" aria-hidden="true" />

<!-- Meaningful standalone icon -->
<keepui-icon name="close-icon" ariaLabel="Cerrar" />

Inputs

| Input | Type | Default | Description | |---|---|---|---| | name | unknown | — | ID of the SVG symbol to render (without the # prefix). | | size | number | 24 | Width and height of the icon in pixels. | | viewBox | string | '0 0 24 24' | viewBox attribute forwarded to the <svg> element. | | ariaLabel | string | '' | Accessible label for standalone icons. When provided, sets role="img" and aria-label on the SVG. When omitted, the SVG is marked aria-hidden="true" (decorative). |


5.5 ImagePreviewComponent

Selector: keepui-image-preview Import: import { ImagePreviewComponent } from '@keepui/ui';

Standalone component that allows the user to pick and preview an image.

This component is fully platform-agnostic. It delegates file picking to whatever FilePort implementation is provided via FILE_PORT.

UI strings are fully internationalised via Transloco (scope 'keepui'). Call provideKeepUiI18n() in your app.config.ts and use KeepUiLanguageService.setLanguage(lang) to change locale at runtime.

Usage:

<keepui-image-preview />

Prerequisites — register providers in app.config.ts:

  • Web: provideKeepUi() + provideKeepUiI18n()
  • Capacitor: provideKeepUiCapacitor() + provideKeepUiI18n()

Public signals (readable from outside)

| Signal | Type | Description | |---|---|---| | imageUrl | Signal<string | null> | URL of the selected image, ready to bind to [src]. | | error | Signal<string | null> | Error message if the last pick operation failed. | | loading | Signal<boolean> | True while the pick operation is in progress. |


5.6 SignalDropdownComponent

Selector: keepui-signal-dropdown Import: import { SignalDropdownComponent } from '@keepui/ui';

Signal-based accessible dropdown / select component.

Fully platform-agnostic — no native API usage. The panel opens in fixed position so it is never clipped by overflow-hidden ancestors. It repositions itself automatically on scroll and resize.

The value and touched properties are model() signals so the component integrates seamlessly with Angular signal-based forms.

<keepui-signal-dropdown
  label="País"
  placeholder="Selecciona un país"
  [options]="countries"
  [(value)]="selectedCountry"
/>

Inputs

| Input | Type | Default | Description | |---|---|---|---| | label | string | '' | Optional label text rendered above the dropdown. | | placeholder | string | '' | Placeholder shown when no value is selected. | | options | unknown | — | Array of options to display in the panel. | | width | SignalDropdownWidth | 'full' | Layout width of the wrapper. | | required | boolean | false | Marks the field as required. Adds aria-required and a visual asterisk. | | errorMessage | string | '' | Human-readable error message shown below the dropdown. Takes precedence over errors[0]. | | errors | readonly string[] | [] | Array of error strings. The first item is displayed when errorMessage is empty. Set together with invalid=true to trigger the error state. | | selectId | string | ``ku-dropdown-${Math.random(| Stableidused to link thewith the trigger. A random suffix is generated by default. | | disabled|boolean|false| Disables the dropdown. | |invalid|boolean|false| Forces the error visual state regardless of thetouched` model. Useful for external form validation. |

Outputs

| Output | Emitter type | Description | |---|---|---| | valueChange | OutputEmitterRef<T | null> | Emitted when the selected value changes. |


5.7 SignalTextareaComponent

Selector: keepui-signal-textarea Import: import { SignalTextareaComponent } from '@keepui/ui';

Signal-based accessible textarea component with character counter, resize control, and integrated error display.

The value and touched properties are model() signals so the component integrates seamlessly with Angular signal-based forms.

<keepui-signal-textarea
  label="Descripción"
  placeholder="Escribe aquí…"
  [rows]="5"
  [maxLength]="500"
  [(value)]="description"
/>

Inputs

| Input | Type | Default | Description | |---|---|---|---| | label | string | '' | Optional label text rendered above the textarea. | | placeholder | string | '' | Placeholder passed to the underlying <textarea>. | | rows | number | 4 | Number of visible text rows. | | width | SignalTextareaWidth | 'full' | Layout width of the wrapper. | | resize | SignalTextareaResize | 'none' | CSS resize behaviour. | | required | boolean | false | Marks the field as required. | | errorMessage | string | '' | Human-readable error message. Takes precedence over errors[0]. | | errors | readonly string[] | [] | Array of error strings. The first item is displayed when errorMessage is empty. Set together with invalid=true to trigger the error state. | | textareaId | string | ``ku-textarea-${Math.random(| Stableidused to link thewith the. A random suffix is generated by default. | | disabled|boolean|false| Disables the textarea. | |maxLength|number | undefined|undefined| Maximum number of characters allowed. Shows a character counter when set. | |invalid|boolean|false| Forces the error visual state regardless of thetouched` model. Useful for external form validation. |


5.8 SignalTextInputComponent

Selector: keepui-signal-text-input Import: import { SignalTextInputComponent } from '@keepui/ui';

Signal-based accessible text input supporting all common HTML input types, leading/trailing icons, a trailing content slot, and a built-in password-visibility toggle (when type="password").

The value and touched properties are model() signals so the component integrates seamlessly with Angular signal-based forms.

Password toggle labels are translated via Transloco (scope 'keepui'). Call provideKeepUiI18n() in your app.config.ts to activate i18n.

<keepui-signal-text-input
  label="Email"
  type="email"
  placeholder="[email protected]"
  leadingIcon="mail-icon"
  [(value)]="email"
/>

<!-- Password with toggle -->
<keepui-signal-text-input
  label="Contraseña"
  type="password"
  [(value)]="password"
/>

Inputs

| Input | Type | Default | Description | |---|---|---|---| | label | string | '' | Optional label text rendered above the input. | | placeholder | string | '' | Placeholder passed to the underlying <input>. | | type | SignalTextInputType | 'text' | HTML type attribute. Use 'password' to enable the visibility toggle. | | width | SignalTextInputWidth | 'full' | Layout width of the wrapper. | | leadingIcon | string | '' | Name of the leading icon (SVG symbol ID). Leave empty for no icon. | | trailingIcon | string | '' | Name of the trailing icon (SVG symbol ID). Ignored when type="password". | | hasTrailingSlot | boolean | false | When true, a slot for custom trailing content is enabled (projects [trailingSlot] content). Overrides trailingIcon. | | required | boolean | false | Marks the field as required. Adds aria-required and a visual asterisk. | | showRequiredIndicator | boolean | true | When false, hides the visual asterisk even if required=true. | | errorMessage | string | '' | Human-readable error message. Takes precedence over errors[0]. | | errors | readonly string[] | [] | Array of error strings. The first item is displayed when errorMessage is empty. Set together with invalid=true to trigger the error state. | | inputId | string | ``ku-text-input-${Math.random(| Stableidused to link thewith the. A random suffix is generated by default. | | disabled|boolean|false| Disables the input. | |invalid|boolean|false| Forces the error visual state regardless of thetouched` model. Useful for external form validation. |


6. Type definitions

Visual style variant of the button.

type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger';

Size mode of the button.

  • md: fixed width (160 px) and height (40 px).
  • auto: height fixed (40 px), width grows with padding to fit content.
type ButtonSize = 'md' | 'auto';

Border-radius style of the button.

  • pill: fully rounded (rounded-full).
  • rounded: moderately rounded (rounded-2xl).
type ButtonShape = 'pill' | 'rounded';

HTML type attribute for the underlying <button> element.

type ButtonType = 'button' | 'submit' | 'reset';
type CardVariant = 'flat' | 'outlined';
type CardPadding = 'none' | 'sm' | 'md' | 'lg' | 'screen';
type CardColors = 'primary' | 'secondary';
type IconActionButtonVariant = 'default' | 'danger';
type IconActionButtonType = 'button' | 'submit' | 'reset';

Layout width of the dropdown wrapper.

type SignalDropdownWidth = 'full' | 'half' | 'auto';

Layout width of the text input wrapper.

type SignalTextInputWidth = 'full' | 'half' | 'auto';

HTML type attribute for the underlying <input> element. Use 'password' to enable the built-in show/hide toggle.

type SignalTextInputType = | 'text'
  | 'email'
  | 'tel'
  | 'number'
  | 'password'
  | 'search'
  | 'url'
  | 'date';

Layout width of the textarea wrapper.

type SignalTextareaWidth = 'full' | 'half' | 'auto';

CSS resize behaviour of the <textarea> element.

  • none → not resizable (default).
  • vertical → user can drag to resize vertically.
  • horizontal → user can drag to resize horizontally.
  • both → user can drag freely.
type SignalTextareaResize = 'none' | 'vertical' | 'horizontal' | 'both';

7. Interfaces & models

FileResult

Represents the result of a file/image selection operation. This model is platform-agnostic and used across all adapters.

interface FileResult {
  /** A data URL (e.g. `data:image/jpeg;base64,...`) or an HTTP/file URL ready to display. */
  dataUrl: string;
  /** MIME type of the selected file, e.g. `image/jpeg`. */
  mimeType: string;
}

FilePort

Platform-agnostic port (interface) for file/image selection.

Provide a concrete implementation via the FILE_PORT injection token.

  • Web: WebFileService
  • Capacitor: CapacitorFileService (from @keepui/ui/capacitor)
interface FilePort {
  /** Opens a platform-native image picker and returns the selected image.
Resolves with a `FileResult` containing a displayable URL and MIME type.
Rejects if the user cancels or an error occurs. */
  pickImage(): Promise<FileResult>;
}

8. Services

KeepUiLanguageService

Service that exposes a public API for changing the active language of all KeepUI components at runtime.

Usage

// Inject anywhere in the host application
const lang = inject(KeepUiLanguageService);

// Switch to Spanish
lang.setLanguage('es');

// Read the active language
console.log(lang.activeLanguage()); // 'es'

Register via provideKeepUiI18n() in app.config.ts.

Public properties:

| Property | Type | Description | |---|---|---| | activeLanguage | — | Signal that reflects the currently active KeepUI locale. | | availableLanguages | readonly KeepUiLanguage[] | Ordered list of all supported locales. |

Public methods:

  • setLanguage(lang: KeepUiLanguage): void — Changes the active language for all KeepUI components.

WebFileService

Web implementation of FilePort.

Uses a hidden <input type="file"> and the FileReader API to let the user pick an image from the file system in a browser environment.

This implementation has no dependency on Capacitor or any native plugin.

Public methods:

  • pickImage(): Promise<FileResult>

9. Internationalisation (i18n)

Use typed constants instead of raw strings:

import { KEEPUI_TRANSLATION_KEYS as T } from '@keepui/ui';

// Example
translocoService.translate(T.IMAGE_PREVIEW.SELECT_IMAGE);

Supported languages: en (English), es (Spanish), de (German)

Translation keys:

| Constant path | Translation key | |---|---| | IMAGE_PREVIEW.SELECT_IMAGE | imagePreview.selectImage | | IMAGE_PREVIEW.LOADING | imagePreview.loading | | IMAGE_PREVIEW.PREVIEW_ALT | imagePreview.previewAlt | | IMAGE_PREVIEW.ERROR_UNEXPECTED | imagePreview.errorUnexpected | | SIGNAL_TEXT_INPUT.SHOW_PASSWORD | signalTextInput.showPassword | | SIGNAL_TEXT_INPUT.HIDE_PASSWORD | signalTextInput.hidePassword |

Changing language at runtime:

import { KeepUiLanguageService } from '@keepui/ui';

const lang = inject(KeepUiLanguageService);
lang.setLanguage('es');  // 'en' | 'es' | 'de'

10. CSS design tokens

Override any variable in your CSS to customise the theme:

:root {
  --keepui-primary:            #3b82f6;
  --keepui-primary-hover:      #2563eb;
  --keepui-primary-active:     #1d4ed8;
  --keepui-primary-foreground: #ffffff;
  --keepui-background:         #f5f5f5;
  --keepui-surface:            #ffffff;
  --keepui-surface-hover:      #f0f0f0;
  --keepui-border:             #e0e0e0;
  --keepui-border-strong:      #cccccc;
  --keepui-text:               #1f2937;
  --keepui-text-muted:         #6b7280;
  --keepui-text-disabled:      #9ca3af;
  --keepui-error:              #dc2626;
  --keepui-error-foreground:   #ffffff;
  --keepui-success:            #16a34a;
  --keepui-warning:            #f59e0b;
  --keepui-shadow-sm:          0 1px 3px rgba(0,0,0,.12);
  --keepui-shadow-md:          0 3px 6px rgba(0,0,0,.15);
  --keepui-shadow-lg:          0 6px 12px rgba(0,0,0,.18);
}

[data-theme="dark"] {
  --keepui-primary:            #60a5fa;
  --keepui-primary-foreground: #0f172a;
  --keepui-background:         #0f172a;
  --keepui-surface:            #1e293b;
  --keepui-surface-hover:      #334155;
  --keepui-border:             #334155;
  --keepui-border-strong:      #475569;
  --keepui-text:               #f1f5f9;
  --keepui-text-muted:         #94a3b8;
  --keepui-text-disabled:      #64748b;
  --keepui-error:              #f87171;
  --keepui-error-foreground:   #0f172a;
  --keepui-success:            #4ade80;
  --keepui-warning:            #fbbf24;
}

11. Tailwind utility classes

Generated automatically after @import "@keepui/ui/styles" with Tailwind v4:

bg-keepui-background      bg-keepui-surface        bg-keepui-surface-hover
bg-keepui-primary         bg-keepui-primary-hover  bg-keepui-primary-active
bg-keepui-error           bg-keepui-success        bg-keepui-warning

text-keepui-text          text-keepui-text-muted   text-keepui-text-disabled
text-keepui-primary       text-keepui-primary-fg   text-keepui-error

border-keepui-border      border-keepui-border-strong  border-keepui-primary

shadow-keepui-sm          shadow-keepui-md         shadow-keepui-lg

focus-visible:ring-keepui-primary

5.10 TabGroupComponent

Selector: keepui-tab-group Import: import { TabGroupComponent, Tab, TabGroupVariant } from '@keepui/ui';

Accessible pill-style tab group implementing the WAI-ARIA tablist pattern. Supports icons, disabled tabs, keyboard navigation (arrow keys, Home, End) and two visual variants. No internal i18n strings — tab labels are provided by the consumer.

<!-- Default variant -->
<keepui-tab-group
  [tabs]="tabs"
  [selectedTabId]="activeTab"
  (tabChange)="activeTab = $event"
  ariaLabel="Main sections"
/>

<!-- Filled variant -->
<keepui-tab-group
  variant="filled"
  [tabs]="tabs"
  [selectedTabId]="activeTab"
  (tabChange)="activeTab = $event"
/>
readonly tabs: Tab[] = [
  { id: 'home',     label: 'Home' },
  { id: 'profile',  label: 'Profile', icon: 'user-icon' },
  { id: 'settings', label: 'Settings', disabled: true },
];

Inputs

| Input | Type | Default | Description | |---|---|---|---| | tabs | Tab[] | (required) | List of tabs to render. | | selectedTabId | string | (required) | ID of the currently active tab. | | variant | TabGroupVariant | 'default' | Visual style: 'default' or 'filled'. | | ariaLabel | string | '' | Accessible label for the tablist element. |

Outputs

| Output | Emitter type | Description | |---|---|---| | tabChange | OutputEmitterRef<string> | Emits the id of the selected tab. |

Tab interface

| Property | Type | Required | Description | |---|---|---|---| | id | string | ✅ | Unique identifier. | | label | string | ✅ | Visible tab label. | | icon | string | — | SVG symbol ID (without #) for an optional icon. | | disabled | boolean | — | When true, the tab is not selectable. Default false. |

Accessibility

  • Container: role="tablist" with optional aria-label.
  • Each button: role="tab", aria-selected, aria-disabled, managed tabindex.
  • Keyboard: ArrowRight/ArrowLeft (and Down/Up) navigate between tabs; Home/End jump to extremes.
  • Focus ring: focus-visible:ring-2 focus-visible:ring-ku-action-primary.
  • Touch target: min-h-[2.75rem] on every tab button.

5.11 StepperComponent

Selector: keepui-stepper Import: import { StepperComponent, StepperStep, StepperSize, StepperOrientation } from '@keepui/ui';

Visual step-progress indicator with optional interactive navigation. Renders numbered circles connected by animated progress bars. Completed steps show a check-mark; the active step is highlighted with a ring; future steps are muted. Steps can carry an icon that replaces the number.

<!-- Read-only progress indicator -->
<keepui-stepper [steps]="steps" [activeIndex]="1" />

<!-- Interactive (allows going back to completed steps) -->
<keepui-stepper
  [steps]="steps"
  [activeIndex]="currentStep"
  (stepChange)="currentStep = $event"
  ariaLabel="Registration process"
/>

<!-- Small, vertical -->
<keepui-stepper
  [steps]="steps"
  [activeIndex]="currentStep"
  size="sm"
  orientation="vertical"
/>
readonly steps: StepperStep[] = [
  { id: '1', label: 'Account' },
  { id: '2', label: 'Profile', icon: 'user-icon' },
  { id: '3', label: 'Plan' },
  { id: '4', label: 'Confirm', disabled: true },
];

Inputs

| Input | Type | Default | Description | |---|---|---|---| | steps | StepperStep[] | (required) | List of steps to render. | | activeIndex | number | 0 | Zero-based index of the currently active step. | | size | StepperSize | 'md' | Size of step circles and connectors: 'md' or 'sm'. | | orientation | StepperOrientation | 'horizontal' | Layout direction: 'horizontal' or 'vertical'. | | ariaLabel | string | '' | Accessible label for the <nav> element. |

Outputs

| Output | Emitter type | Description | |---|---|---| | stepChange | OutputEmitterRef<number> | Emits the zero-based index of the clicked step (completed or active steps only). |

StepperStep interface

| Property | Type | Required | Description | |---|---|---|---| | id | string | ✅ | Unique identifier. | | label | string | ✅ | Label shown below the step circle. | | icon | string | — | SVG symbol ID (without #) rendered inside the circle instead of the step number. | | disabled | boolean | — | When true, the step is not interactive. Default false. |

Accessibility

  • Container: <nav> with optional aria-label.
  • List: role="list" / role="listitem" with aria-current="step" on the active item.
  • Completed and active steps render as <button> elements with aria-label equal to the step label.
  • Future and disabled steps render as inert <span> elements.
  • Focus ring: focus-visible:ring-2 focus-visible:ring-ku-action-primary.
  • Touch target: min-h-[2.75rem] min-w-[2.75rem] on every interactive step bubble.

12. Integration checklist

  • [ ] @keepui/ui installed in package.json
  • [ ] @import "@keepui/ui/styles" in global stylesheet
  • [ ] Tailwind v4 configured (via @tailwindcss/postcss or @tailwindcss/vite)
  • [ ] provideKeepUi() or provideKeepUiCapacitor() registered in app.config.ts
  • [ ] provideKeepUiI18n() registered in app.config.ts
  • [ ] Components imported individually in each standalone component or NgModule
  • [ ] [data-theme="dark"] toggle wired if dark mode switching is needed
  • [ ] KeepUiLanguageService.setLanguage() called if runtime i18n is needed

13. What NOT to do

  • Do not import from @keepui/ui/src/lib/... — only from @keepui/ui or @keepui/ui/capacitor.
  • Do not call both provideKeepUi() and provideKeepUiCapacitor().
  • Do not hardcode FILE_PORT implementations inside components — always use the token.
  • Do not skip @import "@keepui/ui/styles" — without it, all theme utility classes are missing.
  • Do not import @capacitor/* in code that also imports @keepui/ui core.