Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

Ionic Framework Admin & Architecture Guide

Generated June 2026 from ionic-team/ionic-framework at 3da72cd

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

This guide is for engineers who need to understand how Ionic Framework is built, not just how to use it: architects evaluating it, platform owners pinning versions and auditing security, and contributors working inside the monorepo. It documents the repository's structure, the Stencil-based build and codegen pipeline that turns one set of Web Components into four published packages, the configuration and security models, and the testing strategy — all written from the source at the commit stamped in the footer.

For day-to-day application development (installing, using components, theming), see the companion User Guide.


1. Executive Summary

Ionic Framework is the open-source source repository for the Ionic UI toolkit. It is not an application — it is a library monorepo that publishes the @ionic/* packages consumed by app developers.

Attribute Value
Repository ionic-team/ionic-framework
License MIT
Monorepo manager Lerna (lerna.json)
Core version (this snapshot) @ionic/core 8.8.9 (all packages share this version)
Web Component compiler Stencil (@stencil/core 4.43.5)
Published packages @ionic/core, @ionic/angular, @ionic/angular-server, @ionic/react, @ionic/react-router, @ionic/vue, @ionic/vue-router
Component count ~97 ion-* Web Components (under core/src/components/)
Design modes ios, md (Material Design)
Icon set ionicons (^8.0.13)
Native runtime Capacitor 8 (integration points)
Total source 9,428 files, ~2.17M source characters
Min Node >= 16

The central architectural idea: every UI component is authored once as a Stencil Web Component in core/. Stencil's build then runs output targets that auto-generate the Angular, React, and Vue wrapper packages. This is why the components are pixel-identical across frameworks and why all packages move in version lockstep — they are mechanically derived from a single source of truth.

Important

When reasoning about this repo, treat core/ as the product and packages/{angular,react,vue} as generated bindings. Most component behavior lives in core/; the framework packages are thin proxies plus a small amount of hand-written framework-idiomatic glue (routing, lifecycle, controllers, value accessors).


2. Architecture

                         ┌─────────────────────────────────────────────┐
                         │   core/  (@ionic/core)                       │
                         │   ~97 Stencil Web Components (*.tsx)          │
                         │   utils: animation, gesture, overlays,       │
                         │   config, platform, sanitization, transition │
                         └───────────────────┬─────────────────────────┘
                                             │  stencil build
                                             │  (output targets)
              ┌──────────────────────────────┼──────────────────────────────┐
              ▼                               ▼                              ▼
   @stencil/angular-output-target  @stencil/react-output-target   @stencil/vue-output-target
              │                               │                              │
              ▼                               ▼                              ▼
   packages/angular                  packages/react                 packages/vue
   (@ionic/angular)                  (@ionic/react)                 (@ionic/vue)
   + angular/common                  + react-router                 + vue-router
   + angular/standalone              (@ionic/react-router)          (@ionic/vue-router)
   + angular-server (SSR)
              │                               │                              │
              └───────────────────────────────┴──────────────────────────────┘
                                             ▼
                              App developer's project
                              (+ Capacitor for native packaging)

2.1 Layered responsibilities

Layer Location Responsibility
Component source core/src/components/ The actual UI components, authored as Stencil .tsx with scoped/shadow styles in .scss
Core utilities core/src/utils/, core/src/global/ Framework-agnostic services: animation engine, gesture engine, overlay controllers, config, platform detection, sanitization, page transitions, logging
Build/codegen core/stencil.config.ts, core/scripts/ Compiles components and generates the framework proxy files via output targets
Framework bindings packages/{angular,react,vue}/ Generated proxies + hand-written routing, lifecycle, controllers, forms glue
Router integrations packages/{react-router,vue-router}/ Bridge each framework's router to Ionic's stack-based navigation
SSR packages/angular-server/ Server-side rendering support for Angular
Test apps packages/*/test/, core/src/**/test/ Per-framework, per-version end-to-end and screenshot test applications

Note

A large fraction of the 9,428 files are test applications and Playwright screenshot snapshots — e.g. packages/angular/test/apps/ng16…ng20, packages/react/test/apps/react17…react19, and the thousands of *.e2e.ts-snapshots/ directories. These exist to verify the components render identically across framework versions; they are not part of any shipped package.


3. Repository Structure

ionic-framework/
├── core/                     @ionic/core — the Web Components (Stencil)
│   ├── src/
│   │   ├── components/       ~97 ion-* components (each: .tsx + .scss + test/)
│   │   ├── utils/            animation, gesture, overlays, config, platform,
│   │   │                     transition, sanitization, logging, forms, theme
│   │   ├── global/           ionic-global.ts (initialize), config.ts (Config)
│   │   ├── css/              global stylesheets and utility classes
│   │   └── themes/           mode/theme SCSS
│   ├── stencil.config.ts     build config + output targets (THE pipeline)
│   ├── custom-rules/         repo-local ESLint plugin
│   └── scripts/              build, clean, treeshaking, custom-elements
├── packages/
│   ├── angular/              @ionic/angular (NgModule API)
│   │   ├── common/           shared Angular providers/utils (@ionic/angular/common)
│   │   ├── standalone/       @ionic/angular/standalone (standalone components API)
│   │   └── src/schematics/   `ng add` / `ng generate` schematics
│   ├── angular-server/       @ionic/angular-server (SSR)
│   ├── react/                @ionic/react
│   ├── react-router/         @ionic/react-router
│   ├── vue/                  @ionic/vue
│   ├── vue-router/           @ionic/vue-router
│   └── docs/                 docs generation helpers
├── docs/                     CONTRIBUTING.md, per-framework docs
├── BREAKING.md / BREAKING_ARCHIVE/   breaking-change logs
├── CHANGELOG.md / CHANGELOG_ARCHIVE/ release history
├── lerna.json                monorepo configuration
├── renovate.json5            automated dependency updates
└── package.json              root (private; build orchestration only)

Note

The root package.json is private and declares only lerna and semver as devDependencies with a one-line description: "used mainly to execute build scripts. This package is not published to npm." All real package metadata lives in the per-package package.json files.


4. System Requirements

4.1 To build the repository

Requirement Version
Node.js >= 16
Package manager npm (a package-lock.json is committed)
Monorepo tool Lerna ^5.5.2

4.2 To consume the packages (downstream)

Package Key peer/runtime requirements
@ionic/core @stencil/core 4.43.5, ionicons ^8.0.13, tslib ^2.1.0
@ionic/angular Angular >=16 (core, forms, router), rxjs >=7.5, zone.js >=0.13
@ionic/react React + @ionic/react-router for routing
@ionic/vue Vue 3 + @ionic/vue-router for routing

5. The Build & Codegen Pipeline

This is the most important system to understand in the repository. It lives in core/stencil.config.ts.

5.1 Stencil build of @ionic/core

The core build (core/package.json build script) runs:

npm run clean && npm run build.css && stencil build --es5 --docs-json dist/docs.json
  • build.css compiles SCSS to CSS (sass --style compressed src/css:./css) and minifies the bundle (cleancss -O2 -o ./css/ionic.bundle.css).
  • stencil build compiles every *.tsx component into Web Components, produces multiple distribution formats (lazy-loaded dist/, dist/esm/, dist/collection/, custom-elements build), generates the dist/types/ declarations, and emits dist/docs.json (the machine-readable component API used to drive documentation).

The Stencil config sets namespace: 'Ionic', autoprefixCss: true, and uses @stencil/sass for styles. It explicitly groups components into bundles (e.g. ion-app is bundled with ion-router-outlet, ion-content, ion-header, ion-toolbar, ion-title; ion-card with its sub-components) so that related components load together and tree-shaking works at a sensible granularity.

5.2 Output targets — the framework wrappers

The same stencil build runs three output targets that generate the framework packages:

Output target Generates Notes
angularOutputTarget (component) packages/angular/src/directives/proxies.ts + proxies-list.ts outputType: 'component' (for the NgModule API)
angularOutputTarget (standalone) packages/angular/standalone/src/directives/proxies.ts outputType: 'standalone'
reactOutputTarget React component proxies in packages/react from @stencil/react-output-target 0.5.3
vueOutputTarget Vue component proxies in packages/vue from @stencil/vue-output-target 0.10.8

Important

The generated proxy files (proxies.ts) are build artifacts checked into the repo. Do not hand-edit them — they are regenerated by stencil build. The Angular package's build script even runs clean-generated to remove them between builds.

5.3 Excluded components (manual implementations)

The Angular output targets excludeComponents for elements that need hand-written Angular semantics rather than a generated proxy:

  • Overlays that host user components: ion-modal, ion-popover — need Angular's content-projection/ng-template handling.
  • Navigation: ion-router, ion-route, ion-route-redirect, ion-router-link, ion-router-outlet, ion-nav, ion-back-button, ion-tabs — replaced by Angular-router-aware directives.
  • Auxiliary: ion-picker-legacy-column.

The standalone output additionally excludes ion-icon (it comes from ionicons, not @ionic/core, so a generated proxy would import from the wrong place) and the form controls ion-input, ion-input-otp, ion-textarea, ion-searchbar, ion-datetime, ion-segment, ion-checkbox, ion-toggle, ion-range, ion-radio-group, ion-select — these have manually implemented value accessors so Angular forms (ngModel, formControlName) work correctly.

Note

This exclude list is the precise boundary between "mechanically generated" and "hand-written" in the Angular packages. When debugging Angular-specific behavior for these components, look in packages/angular/src/directives/ and packages/angular/common/, not in the generated proxies.

5.4 Per-package build scripts

Package Build approach
@ionic/angular ng-packagr builds the library (build.ng), then build-core.js copies core assets; clean-generated strips generated proxies after
@ionic/react / @ionic/vue TypeScript build of the generated proxies + hand-written modules
@ionic/core Stencil build (above)

The root uses Lerna to orchestrate building packages in dependency order (core first, then the framework packages that depend on it).


6. Core Subsystems (Contributor Reference)

These framework-agnostic services in core/src/ are the engine room. The framework packages re-export them.

6.1 Configuration — core/src/global/config.ts + core/src/utils/config.ts

A singleton Config class backs the global config object:

export class Config {
  private m = new Map<keyof IonicConfig, any>();
  reset(configObj: IonicConfig) { /* replace map */ }
  get(key, fallback?) { /* ... */ }
  getBoolean(key, fallback = false) { /* string 'true' coercion */ }
  getNumber(key, fallback?) { /* parseFloat */ }
  set(key, value) { /* ... */ }
}
export const config = /*@__PURE__*/ new Config();

setupConfig(config) merges the provided object into window.Ionic.config. The config is resolved from three sources (later wins where applicable):

  1. Code — the object passed to setupConfig / provideIonicAngular / setupIonicReact / IonicVue.
  2. URL — configFromURL() reads any query parameter prefixed ionic: (e.g. ?ionic:mode=md).
  3. Session — configFromSession() / saveConfig() persist config under sessionStorage key ionic-persist-config when persistConfig: true.

getMode() returns the active mode, defaulting to 'md' when nothing is configured.

The complete IonicConfig interface (defined in core/src/utils/config.ts) is the authoritative configuration surface — see §8.

6.2 Overlay controllers — core/src/utils/overlays.ts

A generic createController<Opts, Elm>(tagName) factory produces each controller with create/dismiss/getTop. The exported singletons:

Export Tag Options type
alertController ion-alert AlertOptions
actionSheetController ion-action-sheet ActionSheetOptions
loadingController ion-loading LoadingOptions
modalController ion-modal ModalOptions
pickerController ion-picker-legacy PickerOptions
popoverController ion-popover PopoverOptions
toastController ion-toast ToastOptions

createOverlay(tagName, options) builds the element; the file also centralizes Escape-key and hardware-back-button dismissal behavior, wired when the first overlay is created. The string "framework delegate is missing" is thrown here (and in framework-delegate.ts) when a component-hosting overlay is used without a framework delegate.

6.3 Animation engine — core/src/utils/animation/

createAnimation() returns a chainable Animation built on the Web Animations API. It supports element/group targeting (addElement, addAnimation), timing (duration, delay, iterations, direction, easing, fill), property keyframes (from/to/fromTo/keyframes), playback (play/pause/stop/destroy), gesture-driven progress (progressStart/progressStep/progressEnd), and before/after read-write hooks for batched DOM access. Page transitions (iosTransitionAnimation, mdTransitionAnimation) and all overlay enter/leave animations are themselves built with this engine, which is why they are fully overridable via config.

6.4 Gesture engine — core/src/utils/gesture/

createGesture(config: GestureConfig) provides normalized pointer handling with a GestureDetail payload (coordinates, deltas, velocity). Config supports direction, threshold, gesturePriority (collision resolution), passive, maxAngle, disableScroll, blurOnStart, and canStart/onWillStart/onStart/onMove/onEnd/notCaptured callbacks. Swipe-to-go-back, item-sliding, the range knob, refresher, and sheet-modal drag are all built on this.

6.5 Platform detection — core/src/utils/platform.ts

isPlatform(name), getPlatforms(), and the Platforms/PlatformConfig types. Platform detection is also overridable via the config platform key.

6.6 Sanitization — core/src/utils/sanitization/

A DOM sanitizer plus IonicSafeString (a wrapper marking a string as trusted HTML). Governed by the sanitizerEnabled and innerHTMLTemplatesEnabled config keys — see §9 Security.

6.7 Global initialization — core/src/global/ionic-global.ts

initialize(config) is the single entry point each framework calls (Vue's IonicVue.install calls it directly; the other frameworks call it through their setup functions). It applies config, sets the document mode, and bootstraps the global Ionic state.

6.8 Lifecycle constants — core/src/components/nav/constants.ts

LIFECYCLE_WILL_ENTER, LIFECYCLE_DID_ENTER, LIFECYCLE_WILL_LEAVE, LIFECYCLE_DID_LEAVE, LIFECYCLE_WILL_UNLOAD — the event names the page lifecycle is built on.


7. Framework Binding Internals

7.1 Angular

  • packages/angular/src/ — the NgModule API. IonicModule.forRoot(config) (in ionic-module.ts) returns ModuleWithProviders and accepts IonicConfig & OptInAngularFeatures. Exports providers (AlertController, ModalController, …, Platform, Config, NavController, DomController, AngularDelegate), directives, control value accessors, validators, and IonicRouteStrategy.
  • packages/angular/common/ — shared code (@ionic/angular/common) used by both the NgModule and standalone APIs: OverlayBaseController, IonicRouteStrategy, routing utils, overlay proxies.
  • packages/angular/standalone/ — the standalone-components API (@ionic/angular/standalone). provideIonicAngular(config) returns EnvironmentProviders; components and controllers are imported individually. This is the modern, tree-shakeable path.
  • packages/angular/src/schematics/ — ng add @ionic/angular and ng generate schematics. The SchematicsException messages (Could not find project, Invalid projectType, Invalid builder, Could not find file for path) originate here and surface during scaffolding.

Note

OptInAngularFeatures is merged into the config type for both forRoot and provideIonicAngular, so Angular-specific opt-ins are configured alongside the standard IonicConfig.

7.2 React

packages/react/src/ barrels (index.ts) re-export ./components, ./routing, ./lifecycle, ./models, ./contexts, and utilities. setupIonicReact(config) (in components/index.ts) initializes the framework. Routing is split into @ionic/react-router (IonReactRouter, IonReactMemoryRouter, IonReactHashRouter) layered on react-router. Lifecycle hooks (useIonViewWillEnter, etc.) and contexts (NavContext, IonLifeCycleContext) implement the page lifecycle in React idioms.

7.3 Vue

packages/vue/src/index.ts exports component proxies (./proxies), the IonicVue plugin, hand-written components that need Vue-specific behavior (IonPage, IonRouterOutlet, IonTabs, IonTabBar, IonTabButton, IonNav, IonBackButton, IonApp, IonIcon, overlays), composition hooks (useBackButton, useKeyboard, useIonRouter, lifecycle), and controllers. IonicVue.install calls initialize(config) and adds the ion-ce class to the document element (custom-elements build has no hydration, so non-hydrated elements must not be hidden).

7.4 Router integrations

Both router packages exist because Ionic needs a navigation stack on top of URL routing:

  • @ionic/vue-router — createRouter(opts) wraps vue-router's createRouter, then injects navManager (an IonRouter) and viewStacks into the app and patches router.install. Also re-exports createWebHistory/createWebHashHistory/createMemoryHistory.
  • @ionic/react-router — IonReactRouter and the memory/hash variants wrap react-router similarly, maintaining a LocationHistory and view stacks so transitions and back-navigation animate correctly.

8. Configuration Reference

The full IonicConfig interface from core/src/utils/config.ts. All keys are optional.

8.1 Public configuration keys

Key Type Default / Notes
animated boolean false disables all animations/transitions
rippleEffect boolean default true; Material ripple
mode 'ios' | 'md' platform-detected; defaults to md if unset
hardwareBackButton boolean default true on mobile
statusTap boolean default true on mobile; tap status bar to scroll top
backButtonIcon string overrides all ion-back-button icons
backButtonText string overrides all ion-back-button text
backButtonDefaultHref string default fallback href
menuIcon string overrides all ion-menu-button icons
menuType string overrides default ion-menu type
spinner SpinnerTypes overrides all ion-spinner
toggleOnOffLabels boolean overrides ion-toggle on/off labels
loadingSpinner SpinnerTypes | null spinner for loading overlays
refreshingIcon string icon for ion-refresh-content
refreshingSpinner SpinnerTypes | null spinner for ion-refresh-content
infiniteLoadingSpinner SpinnerTypes | null spinner for ion-infinite-scroll-content
swipeBackEnabled boolean iOS swipe-to-go-back across all ion-nav
tabButtonLayout TabButtonLayout layout of tab buttons
toastDuration number default ion-toast duration
navAnimation AnimationBuilder override all nav/router-outlet transitions
sanitizerEnabled boolean enable the basic DOM sanitizer
innerHTMLTemplatesEnabled boolean false by default; allow innerHTML HTML in select components
platform PlatformConfig override platform detection
logLevel 'OFF' | 'ERROR' | 'WARN' framework logging level

8.2 Animation override keys (each an AnimationBuilder)

actionSheetEnter, actionSheetLeave, alertEnter, alertLeave, loadingEnter, loadingLeave, modalEnter, modalLeave, popoverEnter, popoverLeave, toastEnter, toastLeave, pickerEnter, pickerLeave.

8.3 Experimental keys

Key Type Notes
focusManagerPriority ('content' | 'heading' | 'banner')[] Move focus after each transition (a11y)
experimentalCloseWatcher boolean Use the CloseWatcher API; requires hardwareBackButton: true

8.4 Private / internal keys

These are documented in the interface as private and may change without notice; do not depend on them in application code:

keyboardHeight, inputShims, scrollPadding, inputBlurring, scrollAssist, hideCaretOnScroll, persistConfig, _forceStatusbarPadding, _testing, _zoneGate.

Caution

The _-prefixed keys (_forceStatusbarPadding, _testing, _zoneGate) are framework-internal test/integration hooks. Setting them in production configuration is unsupported.


9. Security

9.1 HTML sanitization

Components that render developer-supplied HTML — ion-alert, ion-toast, ion-loading, ion-infinite-scroll-content, ion-refresher-content — are the framework's XSS-sensitive surface. Two config keys govern them:

Key Default Effect
innerHTMLTemplatesEnabled false When false, innerHTML usage is disabled in those components and custom HTML cannot be injected. Must be explicitly enabled to use custom HTML.
sanitizerEnabled (basic sanitizer) Enables Ionic's built-in DOM sanitizer on properties that accept custom HTML.

IonicSafeString lets a developer explicitly mark a string as trusted HTML when sanitization would otherwise strip it.

Caution

The secure default is to not allow innerHTML templates (innerHTMLTemplatesEnabled: false, the constant ENABLE_HTML_CONTENT_DEFAULT = false). Only enable it for content you fully control. Never pass untrusted/user-generated content into these components with the flag enabled — doing so is a direct XSS vector.

9.2 Configuration trust boundary

Because config is also read from the URL (?ionic:*) and from sessionStorage, treat URL-driven config as client-controllable. The public keys are presentational (mode, spinners, animations) so this is low-risk, but never gate security decisions on values that can be set via the ionic: URL prefix.

9.3 Dependency supply chain

The repo uses Renovate (renovate.json5) for automated dependency updates and pins exact versions for build-critical tooling (@stencil/core 4.43.5, @stencil/react-output-target 0.5.3, @stencil/vue-output-target 0.10.8). When auditing, verify these pins match your security policy, since the output-target versions directly determine the generated wrapper code shipped to downstream apps.


10. Operations

There is no server to run — "operations" here means building, testing, and releasing the packages.

10.1 Key npm scripts (core/package.json)

Script Command Purpose
build clean && build.css && stencil build --es5 --docs-json dist/docs.json Full core build
build.css css.sass && css.minify Compile + minify styles
start build.css && stencil build --dev --watch --serve Dev server with watch
test test.spec && test.e2e Spec + e2e
test.spec stencil test --spec --max-workers=2 Jest spec tests
test.e2e npx playwright test Playwright e2e
test.e2e.update-snapshots … --update-snapshots='changed' Refresh changed screenshots
test.treeshake node scripts/treeshaking.js dist/index.js Verify tree-shaking
lint lint.ts && lint.sass && prettier --write ESLint + Stylelint + Prettier
validate lint && test && build && test.treeshake Full pre-release gate
test.e2e.docker docker.build && node ./scripts/docker.mjs Run e2e in a pinned Playwright Docker image

Tip

The validate script is the canonical "is this ready to ship" gate: it lints, tests, builds, and verifies tree-shaking. Run it (or its Angular/Vue equivalents) before opening a PR.

10.2 Release & versioning

Lerna manages versions; all packages publish in lockstep at the same version (8.8.9 in this snapshot). Per-package prerelease scripts run validate then publish via np with a next tag for prereleases. Breaking changes are logged in BREAKING.md (archived in BREAKING_ARCHIVE/) and releases in CHANGELOG.md (archived in CHANGELOG_ARCHIVE/).

10.3 Cross-framework / cross-version testing

The packages/*/test/apps/ directories contain real apps targeting multiple framework versions — Angular ng16 through ng20, React react17/react18/react19, and Vue 3. Combined with Playwright screenshot snapshots under *.e2e.ts-snapshots/, this catches visual and behavioral regressions across the framework version matrix. This is the operational backbone that lets Ionic claim "works identically on Angular/React/Vue."


11. Code Patterns & Conventions

  • Single source, generated bindings. Author components once in core/; never duplicate logic into the framework packages. Framework packages hold only generated proxies + framework-idiomatic glue.
  • Pure-annotation for tree-shaking. Singletons are created with /*@__PURE__*/ annotations (config, the overlay controllers) so bundlers can drop unused ones.
  • Mode-aware styling. Components ship ios and md styles; never hardcode a single platform's look.
  • Direction-aware layout. Use logical start/end slots and -start/-end CSS utilities rather than left/right, for RTL support.
  • Repo-local lint rules. core/custom-rules/ is a local ESLint plugin (eslint-plugin-custom-rules) enforcing Ionic-specific conventions, wired in via file:custom-rules.
  • Stylelint for SCSS (stylelint + stylelint-order) and Prettier with the shared @ionic/prettier-config.

12. Testing Strategy

Layer Tooling Location
Unit / spec Jest via @stencil/core/testing preset (stencil test --spec) colocated *.spec.ts(x)
Component e2e + visual Playwright (@playwright/test ^1.59.1), with @axe-core/playwright for a11y core/src/**/test/**/*.e2e.ts + *.e2e.ts-snapshots/
Cross-framework e2e Per-framework test apps (Cypress/Playwright) packages/*/test/
Tree-shaking scripts/treeshaking.js run in validate

Custom Jest matchers exist for shadow DOM assertions (core/setupJest.js defines toHaveShadowPart, throwing expected toHaveShadowPart to be called with a string … / … on an element with a shadow root when misused).

Note

The skipped/CI-flaky tests visible in community issues (e.g. infinite-scroll scroll-to-top flaky on Safari, issue #30423) indicate where the screenshot/e2e suite is sensitive to timing. Contributors touching scroll or transition code should run the affected e2e specs locally with --update-snapshots='changed' and review the diff carefully.


13. Potential Improvements & Tech Debt

Derived from the source and the open issue tracker at this snapshot:

  • Legacy picker removal. ion-picker-legacy / ion-picker-legacy-column are retained for back-compat alongside the modern ion-picker. A future major can drop them.
  • Deprecated reorder event. core/src/index.ts and the wrapper exports carry a TODO(FW-6590) to remove a deprecated reorder event (ItemReorderEventDetail/ItemReorderCustomEvent).
  • :host-context CSS deprecation (issue #30024). Ionic emits :host-context(), which Lightning CSS flags as deprecated; a CSS-output update is warranted.
  • Newest-framework support. Angular 21 native Vitest support and full zoneless support (issues #30982, #30907, #30804) are in progress; ESM directory-import resolution (#30730) affects modern bundlers.
  • Datetime overlay edge cases. Several open issues (#30504, #31155, #30933, #31151, #31143, #30449) cluster around ion-datetime inside overlays and event reliability — the densest defect area in the tracker.
  • Router query-param handling (#31152). IonRouter.handleHistoryChange compares search-bearing and search-free URLs inconsistently.
  • Config typing TODO. core/src/utils/config.ts carries TODO(FW-2832): types — internal config keys are loosely typed (any map) and could be tightened.

14. Contributing

  1. Read docs/CONTRIBUTING.md and the CODE_OF_CONDUCT.md.
  2. Look for issues labeled help wanted.
  3. Make component changes in core/ — never edit generated proxies.ts files; regenerate them with stencil build.
  4. Run the package's validate gate (lint + test + build + treeshake) before opening a PR.
  5. For visual changes, update Playwright screenshots with test.e2e.update-snapshots and include the diff rationale.
  6. Document breaking changes in BREAKING.md.
  7. The community gathers on the official Discord and Forums (linked from the README); use GitHub issues for bugs and feature requests.

15. Quick Reference

15.1 Published packages

Package Purpose
@ionic/core The Web Components (Stencil)
@ionic/angular Angular NgModule bindings
@ionic/angular/standalone Angular standalone-components bindings
@ionic/angular/common Shared Angular providers/utils
@ionic/angular-server Angular SSR
@ionic/react React bindings
@ionic/react-router React routing integration
@ionic/vue Vue 3 bindings
@ionic/vue-router Vue routing integration

15.2 Framework initialization

Framework Call
Angular (NgModule) IonicModule.forRoot(config)
Angular (standalone) provideIonicAngular(config)
React setupIonicReact(config)
Vue app.use(IonicVue, config) (calls initialize(config))

15.3 Core entry-point exports (@ionic/core)

createAnimation, createGesture, initialize, setupConfig, getMode, componentOnReady, isPlatform, getPlatforms, IonicSafeString, openURL, IonicSlides, lifecycle constants, menuController, and the overlay controllers (alert/actionSheet/modal/loading/picker/popover/toast).

15.4 Build commands

Goal Command (from core/)
Full build npm run build
Dev server npm run start
Spec tests npm run test.spec
E2E tests npm run test.e2e
Pre-release gate npm run validate