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 andpackages/{angular,react,vue}as generated bindings. Most component behavior lives incore/; 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.jsonisprivateand declares onlylernaandsemveras 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-packagepackage.jsonfiles.
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.csscompiles SCSS to CSS (sass --style compressed src/css:./css) and minifies the bundle (cleancss -O2 -o ./css/ionic.bundle.css).stencil buildcompiles every*.tsxcomponent into Web Components, produces multiple distribution formats (lazy-loadeddist/,dist/esm/,dist/collection/, custom-elements build), generates thedist/types/declarations, and emitsdist/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 bystencil build. The Angular package's build script even runsclean-generatedto 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-templatehandling. - 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/andpackages/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):
- Code — the object passed to
setupConfig/provideIonicAngular/setupIonicReact/IonicVue. - URL —
configFromURL()reads any query parameter prefixedionic:(e.g.?ionic:mode=md). - Session —
configFromSession()/saveConfig()persist config undersessionStoragekeyionic-persist-configwhenpersistConfig: 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)(inionic-module.ts) returnsModuleWithProvidersand acceptsIonicConfig & OptInAngularFeatures. Exports providers (AlertController,ModalController, …,Platform,Config,NavController,DomController,AngularDelegate), directives, control value accessors, validators, andIonicRouteStrategy.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)returnsEnvironmentProviders; components and controllers are imported individually. This is the modern, tree-shakeable path.packages/angular/src/schematics/—ng add @ionic/angularandng generateschematics. TheSchematicsExceptionmessages (Could not find project,Invalid projectType,Invalid builder,Could not find file for path) originate here and surface during scaffolding.
Note
OptInAngularFeaturesis merged into the config type for bothforRootandprovideIonicAngular, so Angular-specific opt-ins are configured alongside the standardIonicConfig.
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)wrapsvue-router'screateRouter, then injectsnavManager(anIonRouter) andviewStacksinto the app and patchesrouter.install. Also re-exportscreateWebHistory/createWebHashHistory/createMemoryHistory.@ionic/react-router—IonReactRouterand the memory/hash variants wrapreact-routersimilarly, maintaining aLocationHistoryand 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
innerHTMLtemplates (innerHTMLTemplatesEnabled: false, the constantENABLE_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
validatescript 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
iosandmdstyles; never hardcode a single platform's look. - Direction-aware layout. Use logical
start/endslots and-start/-endCSS 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 viafile: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-columnare retained for back-compat alongside the modernion-picker. A future major can drop them. - Deprecated reorder event.
core/src/index.tsand the wrapper exports carry aTODO(FW-6590)to remove a deprecated reorder event (ItemReorderEventDetail/ItemReorderCustomEvent). :host-contextCSS 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-datetimeinside overlays and event reliability — the densest defect area in the tracker. - Router query-param handling (#31152).
IonRouter.handleHistoryChangecompares search-bearing and search-free URLs inconsistently. - Config typing TODO.
core/src/utils/config.tscarriesTODO(FW-2832): types— internal config keys are loosely typed (anymap) and could be tightened.
14. Contributing
- Read
docs/CONTRIBUTING.mdand theCODE_OF_CONDUCT.md. - Look for issues labeled help wanted.
- Make component changes in
core/— never edit generatedproxies.tsfiles; regenerate them withstencil build. - Run the package's
validategate (lint + test + build + treeshake) before opening a PR. - For visual changes, update Playwright screenshots with
test.e2e.update-snapshotsand include the diff rationale. - Document breaking changes in
BREAKING.md. - 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 |