UI Components
Ionic ships ~100 UI components that render native-looking on iOS, Android, and the web. ion-button, ion-list, ion-card, ion-modal — all theme-able, all accessible by default.
Buttons, cards, lists, toasts, alerts
EXAMPLE
<!-- 1) Buttons -->
<ion-button>Primary</ion-button>
<ion-button color="secondary">Secondary</ion-button>
<ion-button color="danger" fill="outline">Cancel</ion-button>
<ion-button color="success" fill="clear">Maybe</ion-button>
<ion-button expand="block">Full width</ion-button>
<ion-button size="small">Small</ion-button>
<ion-button shape="round">Round</ion-button>
<!-- With an icon -->
<ion-button>
<ion-icon slot="start" name="save"></ion-icon>
Save
</ion-button>
<ion-button>
Next
<ion-icon slot="end" name="arrow-forward"></ion-icon>
</ion-button>
<!-- Icon-only button -->
<ion-button fill="clear" aria-label="Settings">
<ion-icon slot="icon-only" name="settings"></ion-icon>
</ion-button>
<!-- 2) Cards -->
<ion-card>
<img alt="Cover" src="https://example.com/photo.jpg" />
<ion-card-header>
<ion-card-subtitle>Updated 2 hours ago</ion-card-subtitle>
<ion-card-title>Product launch</ion-card-title>
</ion-card-header>
<ion-card-content>
Read about the new features shipping today.
</ion-card-content>
<ion-button fill="clear">Read more</ion-button>
</ion-card>
<!-- 3) Lists + items -->
<ion-list>
<ion-list-header><ion-label>Settings</ion-label></ion-list-header>
<ion-item button (click)="openProfile()">
<ion-icon slot="start" name="person"></ion-icon>
<ion-label>Profile</ion-label>
<ion-note slot="end">Ada</ion-note>
</ion-item>
<ion-item>
<ion-icon slot="start" name="notifications"></ion-icon>
<ion-label>Notifications</ion-label>
<ion-toggle slot="end"></ion-toggle>
</ion-item>
<ion-item>
<ion-icon slot="start" name="moon"></ion-icon>
<ion-label>Theme</ion-label>
<ion-select slot="end" interface="action-sheet">
<ion-select-option value="light">Light</ion-select-option>
<ion-select-option value="dark">Dark</ion-select-option>
<ion-select-option value="auto">Auto</ion-select-option>
</ion-select>
</ion-item>
<ion-item button (click)="logout()" detail="false" color="danger">
<ion-icon slot="start" name="log-out"></ion-icon>
<ion-label>Log out</ion-label>
</ion-item>
</ion-list>
<!-- 4) Sliding items — swipe for actions -->
<ion-list>
<ion-item-sliding *ngFor="let m of messages">
<ion-item-options side="start">
<ion-item-option color="primary" (click)="archive(m)">
<ion-icon slot="icon-only" name="archive"></ion-icon>
</ion-item-option>
</ion-item-options>
<ion-item>
<ion-label>
<h3>{{ m.from }}</h3>
<p>{{ m.preview }}</p>
</ion-label>
</ion-item>
<ion-item-options side="end">
<ion-item-option color="danger" (click)="delete(m)">
<ion-icon slot="icon-only" name="trash"></ion-icon>
</ion-item-option>
</ion-item-options>
</ion-item-sliding>
</ion-list>
<!-- 5) Toast — quick feedback -->
// Angular
import { ToastController } from '@ionic/angular';
constructor(private toast: ToastController) {}
async showToast() {
const t = await this.toast.create({
message: 'Saved.',
duration: 2000,
position: 'bottom',
color: 'success',
buttons: [{ text: 'Undo', handler: () => this.undo() }],
});
await t.present();
}
<!-- 6) Alert — confirmation dialog -->
import { AlertController } from '@ionic/angular';
constructor(private alert: AlertController) {}
async confirm() {
const a = await this.alert.create({
header: 'Delete this item?',
message: 'This action cannot be undone.',
buttons: [
{ text: 'Cancel', role: 'cancel' },
{ text: 'Delete', role: 'destructive', handler: () => this.doDelete() },
],
});
await a.present();
}
<!-- 7) Modal — sheet-style + full-screen -->
import { ModalController } from '@ionic/angular';
import { EditPage } from './edit.page';
async openEdit(id: string) {
const m = await this.modalCtrl.create({
component: EditPage,
componentProps: { id },
breakpoints: [0, 0.4, 0.8, 1],
initialBreakpoint: 0.4,
});
await m.present();
const { data } = await m.onDidDismiss();
if (data?.saved) this.refresh();
}
<!-- 8) Refresher — pull-to-refresh -->
<ion-content>
<ion-refresher slot="fixed" (ionRefresh)="refresh($event)">
<ion-refresher-content></ion-refresher-content>
</ion-refresher>
<ion-list>…</ion-list>
</ion-content>
async refresh(ev) {
await this.loadData();
ev.target.complete();
}
<!-- 9) Infinite scroll -->
<ion-content>
<ion-list>…</ion-list>
<ion-infinite-scroll (ionInfinite)="loadMore($event)">
<ion-infinite-scroll-content loadingText="Loading…"></ion-infinite-scroll-content>
</ion-infinite-scroll>
</ion-content>
<!-- 10) Theming -->
<!-- variables.scss -->
/*
:root {
--ion-color-primary: #0ea5e9;
--ion-color-primary-shade: #0284c7;
--ion-color-primary-tint: #38bdf8;
}
[data-theme='dark'] {
--ion-background-color: #0b0b0b;
--ion-text-color: #eee;
}
*/
<!-- 11) Pick the right component -->
<!-- Single tap action ion-button (with fill / color / size variants) -->
<!-- Sheet of options ion-action-sheet -->
<!-- Confirm / inform ion-alert (single button or two) -->
<!-- Brief feedback ion-toast -->
<!-- Long-form input ion-modal (with breakpoints for bottom-sheet) -->
<!-- Multi-step flow ion-modal + ion-segment -->
<!-- List of actions on a row ion-item-sliding -->
Why it matters
Ionic components are accessible (ARIA roles, keyboard focus) and theme-able (CSS custom properties) out of the box. Resist re-inventing — most native-app interactions already have a matching ion-* component.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
<ion-button color="primary" (click)="save()">Save</ion-button>
<ion-card>
<ion-card-header><ion-card-title>Title</ion-card-title></ion-card-header>
<ion-card-content>Content</ion-card-content>
</ion-card>
Try it Yourself »
Exercise
Primary call-to-action element.
<ion-
>Save</ion-
>
Six letters.
Discussion
Loading…