UNPKG

@capgo/capgo-skills

Version:

55 agent skills for Capacitor mobile development

145 lines (118 loc) • 5.27 kB
# Ionic Component Patterns Load when writing pages, lists, forms, overlays, or tabs. Examples use React (Ionic 9 + React Router 6); Vue/Angular use the same components with `ion-*` tags or framework wrappers. ## App entry (React) ```tsx import { IonApp, IonRouterOutlet, setupIonicReact } from '@ionic/react'; import { IonReactRouter } from '@ionic/react-router'; import { Route, Navigate } from 'react-router-dom'; import '@ionic/react/css/core.css'; import '@ionic/react/css/normalize.css'; import '@ionic/react/css/structure.css'; import '@ionic/react/css/typography.css'; import '@ionic/react/css/palettes/dark.system.css'; // optional dark mode import './theme/variables.css'; setupIonicReact(); // optional config: { mode: 'ios' } forces one mode everywhere export default function App() { return ( <IonApp> <IonReactRouter> <IonRouterOutlet> <Route path="/home" element={<Home />} /> <Route path="/" element={<Navigate to="/home" replace />} /> </IonRouterOutlet> </IonReactRouter> </IonApp> ); } ``` Vue: `app.use(IonicVue)` + `@ionic/vue/css/*`. Angular (Ionic 9): `providers: [provideIonicAngular({})]`, components imported from `@ionic/angular`, CSS `@import '@ionic/angular/css/core.css';` (no `~`). ## Page shell ```tsx <IonPage> <IonHeader translucent> <IonToolbar> <IonButtons slot="start"><IonBackButton defaultHref="/home" /></IonButtons> <IonTitle>Settings</IonTitle> </IonToolbar> </IonHeader> <IonContent fullscreen> <IonHeader collapse="condense"> <IonToolbar><IonTitle size="large">Settings</IonTitle></IonToolbar> </IonHeader> {/* content */} </IonContent> </IonPage> ``` `translucent` + `fullscreen` + condensed header = iOS large-title pattern; MD ignores the condense header. ## Lists ```tsx <IonList inset> <IonItem button detail routerLink="/profile"> <IonIcon icon={personOutline} slot="start" aria-hidden="true" /> <IonLabel> <h2>Profile</h2> <p>Name, photo</p> </IonLabel> </IonItem> <IonItemSliding> <IonItem><IonLabel>Swipe me</IonLabel></IonItem> <IonItemOptions side="end"> <IonItemOption color="danger" onClick={remove}>Delete</IonItemOption> </IonItemOptions> </IonItemSliding> </IonList> ``` Long lists: virtualize with a library (e.g. `@tanstack/react-virtual`, `vue-virtual-scroller`) using `IonContent`'s scroll element; `ion-virtual-scroll` was removed in Ionic 6. Infinite loading: `IonInfiniteScroll` + call `complete()` on the event target. ## Forms (modern syntax, required since Ionic 8) ```tsx <IonList> <IonItem> <IonInput label="Email" labelPlacement="floating" type="email" autocomplete="email" inputmode="email" errorText="Invalid email" /> </IonItem> <IonItem> <IonSelect label="Country" labelPlacement="stacked" interface="action-sheet"> <IonSelectOption value="fr">France</IonSelectOption> </IonSelect> </IonItem> <IonItem> <IonToggle checked={on} onIonChange={(e) => setOn(e.detail.checked)}>Notifications</IonToggle> </IonItem> </IonList> ``` - Validation styling: add `ion-touched` and `ion-invalid` / `ion-valid` classes (framework form libs can toggle them); `errorText` / `helperText` show below. - Ionic 9: `autocorrect` is boolean (default `false`); floating labels float only on focus or value. - Inputs need `font-size >= 16px` on iOS to avoid zoom (Ionic default is fine; do not shrink it). ## Overlays ```tsx <IonButton id="open-sheet">Filters</IonButton> <IonModal trigger="open-sheet" initialBreakpoint={0.5} breakpoints={[0, 0.5, 1]}> <IonContent className="ion-padding">...</IonContent> </IonModal> ``` - Sheet handle in Ionic 9 is focusable and cycles breakpoints (`handleBehavior="cycle"` default). - Use `presentingElement` (the page element) for iOS card-style modals. - Alerts/toasts/action sheets: `useIonAlert`, `useIonToast`, `useIonActionSheet` (React) or the controllers (Angular/Vue). - Pickers: `IonPicker` + `IonPickerColumn` (inline) or `IonDatetime`. `ion-picker-legacy` and `pickerController` are removed in Ionic 9. ## Tabs ```tsx <IonTabs> <IonRouterOutlet> <Route path="/tabs/home" element={<Home />} /> <Route path="/tabs/search" element={<Search />} /> <Route path="/tabs" element={<Navigate to="/tabs/home" replace />} /> </IonRouterOutlet> <IonTabBar slot="bottom"> <IonTabButton tab="home" href="/tabs/home"><IonIcon icon={home} /><IonLabel>Home</IonLabel></IonTabButton> <IonTabButton tab="search" href="/tabs/search"><IonIcon icon={search} /><IonLabel>Search</IonLabel></IonTabButton> </IonTabBar> </IonTabs> ``` Parent route must match nested paths (`path="/tabs/*"` in React Router 6). Each tab keeps its own stack; do not navigate between tabs with `router.back()`. ## Navigation API - React: `useIonRouter()` -> `router.push('/x', 'forward')`, `router.goBack()`. - Vue: `useIonRouter()` or `router.push`. - Angular: `NavController.navigateForward('/x')`. - Swipe-back: `swipeGesture` prop on `ion-router-outlet` (Ionic 9; default `true` iOS, `false` MD). ## Lifecycle Use `useIonViewWillEnter` / `ionViewWillEnter` for refresh-on-return; framework mount hooks do not re-run when navigating back to a cached page.