> ionic

Expert guidance for Ionic, the open-source framework for building cross-platform mobile, desktop, and progressive web apps using web technologies (HTML, CSS, JavaScript/TypeScript). Helps developers build apps with Ionic's UI components, integrate with native device APIs via Capacitor, and deploy to iOS, Android, and web from a single codebase.

fetch
$curl "https://skillshub.wtf/TerminalSkills/skills/ionic?format=md"
SKILL.mdionic

Ionic — Cross-Platform Apps with Web Technologies

Overview

Ionic, the open-source framework for building cross-platform mobile, desktop, and progressive web apps using web technologies (HTML, CSS, JavaScript/TypeScript). Helps developers build apps with Ionic's UI components, integrate with native device APIs via Capacitor, and deploy to iOS, Android, and web from a single codebase.

Instructions

Project Setup

# Install Ionic CLI
npm install -g @ionic/cli

# Create a new project (React, Angular, or Vue)
ionic start my-app tabs --type=react
cd my-app

# Run in browser
ionic serve

# Add native platforms
ionic cap add ios
ionic cap add android

# Build and sync to native
ionic cap sync
ionic cap open ios          # Opens Xcode
ionic cap open android      # Opens Android Studio

UI Components

// src/pages/Home.tsx — Ionic React component with native-feeling UI
// Ionic provides 100+ UI components that adapt to iOS/Android automatically.

import {
  IonContent, IonHeader, IonPage, IonTitle, IonToolbar,
  IonList, IonItem, IonLabel, IonBadge, IonSearchbar,
  IonRefresher, IonRefresherContent, IonFab, IonFabButton,
  IonIcon, IonSegment, IonSegmentButton, IonCard, IonCardHeader,
  IonCardTitle, IonCardContent, IonChip, IonAvatar,
} from "@ionic/react";
import { add, filterOutline } from "ionicons/icons";
import { useState } from "react";

const Home: React.FC = () => {
  const [segment, setSegment] = useState("all");
  const [searchText, setSearchText] = useState("");

  const handleRefresh = async (event: CustomEvent) => {
    await fetchTasks();
    event.detail.complete();    // Dismiss the refresher spinner
  };

  return (
    <IonPage>
      <IonHeader>
        <IonToolbar>
          <IonTitle>Tasks</IonTitle>
        </IonToolbar>
        <IonToolbar>
          <IonSearchbar
            value={searchText}
            onIonInput={(e) => setSearchText(e.detail.value ?? "")}
            placeholder="Search tasks..."
          />
        </IonToolbar>
        <IonToolbar>
          <IonSegment value={segment} onIonChange={(e) => setSegment(e.detail.value as string)}>
            <IonSegmentButton value="all"><IonLabel>All</IonLabel></IonSegmentButton>
            <IonSegmentButton value="active"><IonLabel>Active</IonLabel></IonSegmentButton>
            <IonSegmentButton value="done"><IonLabel>Done</IonLabel></IonSegmentButton>
          </IonSegment>
        </IonToolbar>
      </IonHeader>

      <IonContent>
        <IonRefresher slot="fixed" onIonRefresh={handleRefresh}>
          <IonRefresherContent />
        </IonRefresher>

        <IonList>
          {tasks.map((task) => (
            <IonItem key={task.id} routerLink={`/task/${task.id}`}>
              <IonAvatar slot="start">
                <img src={task.assignee.avatar} alt="" />
              </IonAvatar>
              <IonLabel>
                <h2>{task.title}</h2>
                <p>{task.description}</p>
              </IonLabel>
              <IonBadge slot="end" color={task.priority === "high" ? "danger" : "medium"}>
                {task.priority}
              </IonBadge>
            </IonItem>
          ))}
        </IonList>

        <IonFab vertical="bottom" horizontal="end" slot="fixed">
          <IonFabButton routerLink="/task/new">
            <IonIcon icon={add} />
          </IonFabButton>
        </IonFab>
      </IonContent>
    </IonPage>
  );
};

Native APIs with Capacitor

// src/services/native.ts — Access device features via Capacitor plugins
import { Camera, CameraResultType, CameraSource } from "@capacitor/camera";
import { Geolocation } from "@capacitor/geolocation";
import { LocalNotifications } from "@capacitor/local-notifications";
import { Share } from "@capacitor/share";
import { Haptics, ImpactStyle } from "@capacitor/haptics";
import { Preferences } from "@capacitor/preferences";

// Camera — take photo or pick from gallery
export async function takePhoto(): Promise<string> {
  const image = await Camera.getPhoto({
    quality: 80,
    allowEditing: false,
    resultType: CameraResultType.Uri,
    source: CameraSource.Prompt,          // Let user choose camera or gallery
  });
  return image.webPath!;
}

// Geolocation
export async function getCurrentPosition() {
  const coords = await Geolocation.getCurrentPosition({
    enableHighAccuracy: true,
  });
  return {
    lat: coords.coords.latitude,
    lng: coords.coords.longitude,
  };
}

// Local notifications
export async function scheduleReminder(title: string, body: string, date: Date) {
  await LocalNotifications.schedule({
    notifications: [{
      title,
      body,
      id: Date.now(),
      schedule: { at: date },
    }],
  });
}

// Share
export async function shareContent(title: string, text: string, url?: string) {
  await Share.share({ title, text, url });
}

// Haptic feedback
export async function hapticTap() {
  await Haptics.impact({ style: ImpactStyle.Light });
}

// Local storage (key-value, persists across app restarts)
export async function savePreference(key: string, value: string) {
  await Preferences.set({ key, value });
}

export async function getPreference(key: string): Promise<string | null> {
  const { value } = await Preferences.get({ key });
  return value;
}

Theming

/* src/theme/variables.css — Custom theme */
:root {
  --ion-color-primary: #4f46e5;
  --ion-color-primary-rgb: 79, 70, 229;
  --ion-color-primary-contrast: #ffffff;
  --ion-color-primary-shade: #463ec9;
  --ion-color-primary-tint: #6158e8;

  --ion-color-secondary: #06b6d4;
  --ion-color-success: #22c55e;
  --ion-color-warning: #f59e0b;
  --ion-color-danger: #ef4444;

  --ion-font-family: 'Inter', system-ui, sans-serif;
}

/* Dark mode — Ionic auto-detects system preference */
@media (prefers-color-scheme: dark) {
  :root {
    --ion-background-color: #0f172a;
    --ion-text-color: #e2e8f0;
    --ion-card-background: #1e293b;
  }
}

Installation

npm install -g @ionic/cli
npm install @ionic/react @ionic/react-router
npm install @capacitor/core @capacitor/cli
npm install @capacitor/camera @capacitor/geolocation  # Per-plugin

Examples

Example 1: Setting up Ionic with a custom configuration

User request:

I just installed Ionic. Help me configure it for my TypeScript + React workflow with my preferred keybindings.

The agent creates the configuration file with TypeScript-aware settings, configures relevant plugins/extensions for React development, sets up keyboard shortcuts matching the user's preferences, and verifies the setup works correctly.

Example 2: Extending Ionic with custom functionality

User request:

I want to add a custom ui components to Ionic. How do I build one?

The agent scaffolds the extension/plugin project, implements the core functionality following Ionic's API patterns, adds configuration options, and provides testing instructions to verify it works end-to-end.

Guidelines

  1. Capacitor over Cordova — Capacitor is Ionic's modern native runtime; it supports any web framework and has better plugin ecosystem
  2. Platform-adaptive components — Ionic components auto-adapt to iOS/Android look; don't override platform styles unless necessary
  3. Lazy load pages — Use React.lazy or Angular lazy modules for each page; keeps initial bundle small
  4. Test in browser first — Develop and debug with ionic serve; only test on device for native features (camera, GPS)
  5. Use Ionic's CSS utilities — Ionic includes padding, margin, text alignment utilities; avoid writing custom CSS for spacing
  6. Progressive Web App first — Ionic apps are PWAs by default; test the web version before adding native platforms
  7. Capacitor plugins for native — Always use Capacitor plugins over direct Cordova plugins; they have better TypeScript support
  8. Live reload on deviceionic cap run ios --livereload --external for instant feedback during native testing

> related_skills --same-repo

> zustand

You are an expert in Zustand, the small, fast, and scalable state management library for React. You help developers manage global state without boilerplate using Zustand's hook-based stores, selectors for performance, middleware (persist, devtools, immer), computed values, and async actions — replacing Redux complexity with a simple, un-opinionated API in under 1KB.

> zoho

Integrate and automate Zoho products. Use when a user asks to work with Zoho CRM, Zoho Books, Zoho Desk, Zoho Projects, Zoho Mail, or Zoho Creator, build custom integrations via Zoho APIs, automate workflows with Deluge scripting, sync data between Zoho apps and external systems, manage leads and deals, automate invoicing, build custom Zoho Creator apps, set up webhooks, or manage Zoho organization settings. Covers Zoho CRM, Books, Desk, Projects, Creator, and cross-product integrations.

> zod

You are an expert in Zod, the TypeScript-first schema declaration and validation library. You help developers define schemas that validate data at runtime AND infer TypeScript types at compile time — eliminating the need to write types and validators separately. Used for API input validation, form validation, environment variables, config files, and any data boundary.

> zipkin

Deploy and configure Zipkin for distributed tracing and request flow visualization. Use when a user needs to set up trace collection, instrument Java/Spring or other services with Zipkin, analyze service dependencies, or configure storage backends for trace data.

┌ stats

installs/wk0
░░░░░░░░░░
github stars17
███░░░░░░░
first seenMar 17, 2026
└────────────

┌ repo

TerminalSkills/skills
by TerminalSkills
└────────────

┌ tags

└────────────