skills/konsta-ui/SKILL.md
Guide to using Konsta UI for pixel-perfect iOS and Material Design components in Capacitor apps. Works with React, Vue, and Svelte. Use this skill when users want native-looking UI without Ionic, or prefer a lighter framework.
npx skillsauth add cap-go/capacitor-skills konsta-uiInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Build pixel-perfect iOS and Material Design apps with Konsta UI.
Konsta UI provides:
# React
npm install konsta
# Vue
npm install konsta
# Svelte
npm install konsta
# Required: Tailwind CSS
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
// tailwind.config.js
const konstaConfig = require('konsta/config');
module.exports = konstaConfig({
content: [
'./src/**/*.{js,ts,jsx,tsx,vue,svelte}',
],
// Extend or override Konsta config
theme: {
extend: {},
},
});
// App.tsx
import { App, Page, Navbar, Block } from 'konsta/react';
export default function MyApp() {
return (
<App theme="ios"> {/* or theme="material" */}
<Page>
<Navbar title="My App" />
<Block>
<p>Hello Konsta UI!</p>
</Block>
</Page>
</App>
);
}
<!-- App.vue -->
<template>
<k-app theme="ios">
<k-page>
<k-navbar title="My App" />
<k-block>
<p>Hello Konsta UI!</p>
</k-block>
</k-page>
</k-app>
</template>
<script setup>
import { kApp, kPage, kNavbar, kBlock } from 'konsta/vue';
</script>
import {
App,
Page,
Navbar,
NavbarBackLink,
Block,
BlockTitle,
} from 'konsta/react';
function MyPage() {
return (
<App theme="ios">
<Page>
<Navbar
title="Page Title"
subtitle="Subtitle"
left={<NavbarBackLink onClick={() => history.back()} />}
/>
<BlockTitle>Section Title</BlockTitle>
<Block strong inset>
<p>Block content with rounded corners and padding.</p>
</Block>
</Page>
</App>
);
}
import {
List,
ListItem,
ListInput,
ListButton,
} from 'konsta/react';
import { ChevronRight } from 'framework7-icons/react';
function MyList() {
return (
<>
{/* Simple list */}
<List>
<ListItem title="Item 1" />
<ListItem title="Item 2" />
<ListItem title="Item 3" />
</List>
{/* List with details */}
<List strong inset>
<ListItem
title="John Doe"
subtitle="Designer"
text="Additional info text"
media={<img src="/avatar.jpg" className="w-10 h-10 rounded-full" />}
link
/>
<ListItem
title="Settings"
after="On"
link
/>
</List>
{/* Form list */}
<List strongIos insetIos>
<ListInput
label="Email"
type="email"
placeholder="Enter email"
/>
<ListInput
label="Password"
type="password"
placeholder="Enter password"
/>
<ListButton>Login</ListButton>
</List>
</>
);
}
import {
List,
ListInput,
Toggle,
Radio,
Checkbox,
Stepper,
Range,
} from 'konsta/react';
import { useState } from 'react';
function MyForm() {
const [toggle, setToggle] = useState(false);
const [gender, setGender] = useState('male');
return (
<List strongIos insetIos>
{/* Text inputs */}
<ListInput
label="Name"
type="text"
placeholder="Your name"
clearButton
/>
<ListInput
label="Email"
type="email"
placeholder="Email address"
/>
<ListInput
label="Bio"
type="textarea"
placeholder="About yourself"
inputClassName="!h-20 resize-none"
/>
{/* Toggle */}
<ListItem
title="Notifications"
after={
<Toggle
checked={toggle}
onChange={() => setToggle(!toggle)}
/>
}
/>
{/* Radio */}
<ListItem
title="Male"
media={
<Radio
checked={gender === 'male'}
onChange={() => setGender('male')}
/>
}
/>
<ListItem
title="Female"
media={
<Radio
checked={gender === 'female'}
onChange={() => setGender('female')}
/>
}
/>
{/* Checkbox */}
<ListItem
title="Agree to terms"
media={<Checkbox />}
/>
{/* Stepper */}
<ListItem
title="Quantity"
after={<Stepper value={1} min={1} max={10} />}
/>
{/* Range */}
<ListItem
title="Volume"
innerChildren={<Range value={50} />}
/>
</List>
);
}
import { Button, Segmented, SegmentedButton } from 'konsta/react';
import { useState } from 'react';
function Buttons() {
const [active, setActive] = useState(0);
return (
<div className="space-y-4 p-4">
{/* Button variants */}
<Button>Default</Button>
<Button large>Large</Button>
<Button small>Small</Button>
<Button rounded>Rounded</Button>
<Button outline>Outline</Button>
<Button clear>Clear</Button>
<Button tonal>Tonal</Button>
{/* Colors */}
<Button colors={{ fillBg: 'bg-red-500', fillText: 'text-white' }}>
Custom Color
</Button>
{/* Disabled */}
<Button disabled>Disabled</Button>
{/* Segmented control */}
<Segmented strong>
<SegmentedButton active={active === 0} onClick={() => setActive(0)}>
Tab 1
</SegmentedButton>
<SegmentedButton active={active === 1} onClick={() => setActive(1)}>
Tab 2
</SegmentedButton>
<SegmentedButton active={active === 2} onClick={() => setActive(2)}>
Tab 3
</SegmentedButton>
</Segmented>
</div>
);
}
import { Card, Button } from 'konsta/react';
function Cards() {
return (
<Card>
<img
src="/card-image.jpg"
className="w-full h-48 object-cover"
alt=""
/>
<div className="p-4">
<h3 className="font-bold text-lg">Card Title</h3>
<p className="text-gray-500 mt-2">
Card description text goes here. This is a standard
card with image, title, and content.
</p>
<div className="flex gap-2 mt-4">
<Button small>Action 1</Button>
<Button small outline>Action 2</Button>
</div>
</div>
</Card>
);
}
import {
Dialog,
DialogButton,
Sheet,
Popup,
Button,
Page,
Navbar,
Block,
} from 'konsta/react';
import { useState } from 'react';
function Dialogs() {
const [dialogOpen, setDialogOpen] = useState(false);
const [sheetOpen, setSheetOpen] = useState(false);
const [popupOpen, setPopupOpen] = useState(false);
return (
<>
<Button onClick={() => setDialogOpen(true)}>Open Dialog</Button>
<Button onClick={() => setSheetOpen(true)}>Open Sheet</Button>
<Button onClick={() => setPopupOpen(true)}>Open Popup</Button>
{/* Alert dialog */}
<Dialog
opened={dialogOpen}
onBackdropClick={() => setDialogOpen(false)}
title="Dialog Title"
content="Dialog content goes here."
buttons={
<>
<DialogButton onClick={() => setDialogOpen(false)}>
Cancel
</DialogButton>
<DialogButton strong onClick={() => setDialogOpen(false)}>
OK
</DialogButton>
</>
}
/>
{/* Bottom sheet */}
<Sheet
opened={sheetOpen}
onBackdropClick={() => setSheetOpen(false)}
>
<div className="p-4">
<h2 className="font-bold text-lg mb-4">Sheet Title</h2>
<p>Sheet content</p>
<Button onClick={() => setSheetOpen(false)} className="mt-4">
Close
</Button>
</div>
</Sheet>
{/* Full page popup */}
<Popup opened={popupOpen} onBackdropClick={() => setPopupOpen(false)}>
<Page>
<Navbar
title="Popup"
right={
<Button clear onClick={() => setPopupOpen(false)}>
Close
</Button>
}
/>
<Block>Popup content</Block>
</Page>
</Popup>
</>
);
}
import { App, Page, Tabbar, TabbarLink, Icon } from 'konsta/react';
import { Home, Search, Person } from 'framework7-icons/react';
import { useState } from 'react';
function TabsApp() {
const [activeTab, setActiveTab] = useState('home');
return (
<App theme="ios">
<Page>
{/* Page content based on active tab */}
{activeTab === 'home' && <HomeContent />}
{activeTab === 'search' && <SearchContent />}
{activeTab === 'profile' && <ProfileContent />}
{/* Tabbar */}
<Tabbar labels className="left-0 bottom-0 fixed">
<TabbarLink
active={activeTab === 'home'}
onClick={() => setActiveTab('home')}
icon={<Home />}
label="Home"
/>
<TabbarLink
active={activeTab === 'search'}
onClick={() => setActiveTab('search')}
icon={<Search />}
label="Search"
/>
<TabbarLink
active={activeTab === 'profile'}
onClick={() => setActiveTab('profile')}
icon={<Person />}
label="Profile"
/>
</Tabbar>
</Page>
</App>
);
}
import { App } from 'konsta/react';
// Auto-detect platform
<App theme="parent">
// Force iOS style
<App theme="ios">
// Force Material style
<App theme="material">
import { App } from 'konsta/react';
// Auto dark mode (follows system)
<App dark>
// Explicit dark mode
<App dark={true}>
// Explicit light mode
<App dark={false}>
// tailwind.config.js
const konstaConfig = require('konsta/config');
module.exports = konstaConfig({
theme: {
extend: {
colors: {
primary: {
DEFAULT: '#6366f1',
dark: '#4f46e5',
},
},
},
},
// Override Konsta's primary color
konpistaConfig: {
colors: {
primary: '#6366f1',
},
},
});
// Override individual component colors
<Button
colors={{
fillBg: 'bg-indigo-500',
fillActiveBg: 'bg-indigo-600',
fillText: 'text-white',
}}
>
Custom Button
</Button>
<Toggle
colors={{
bgChecked: 'bg-green-500',
}}
/>
import { App, Page } from 'konsta/react';
function MyApp() {
return (
<App
theme="ios"
safeAreas // Enable safe area handling
>
<Page>
{/* Content respects safe areas */}
</Page>
</App>
);
}
import { App, Page, Button } from 'konsta/react';
import { Capacitor } from '@capacitor/core';
function MyApp() {
const isNative = Capacitor.isNativePlatform();
return (
<App
theme={Capacitor.getPlatform() === 'ios' ? 'ios' : 'material'}
safeAreas={isNative}
>
<Page>
<Button onClick={handleNativeAction}>
Native Action
</Button>
</Page>
</App>
);
}
| Feature | Konsta UI | Ionic | |---------|-----------|-------| | Bundle Size | ~30KB | ~200KB | | Components | ~40 | ~100+ | | Tailwind Integration | Native | Possible | | Routing | External | Built-in | | Framework Support | React, Vue, Svelte | React, Vue, Angular | | Native Features | UI only | UI + Plugins |
Choose Konsta when:
Choose Ionic when:
// Lazy load heavy components
import { lazy, Suspense } from 'react';
const HeavyComponent = lazy(() => import('./HeavyComponent'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<HeavyComponent />
</Suspense>
);
}
// Konsta components are accessible by default
// Add labels for screen readers
<ListInput
label="Email"
type="email"
placeholder="Enter email"
// aria-label is automatically set from label
/>
// For icon-only buttons
<Button aria-label="Close menu">
<Icon name="close" />
</Button>
development
Complete guide to handling safe areas in Capacitor apps for iPhone notch, Dynamic Island, home indicator, and Android cutouts. Covers CSS, JavaScript, and native solutions. Use this skill when users have layout issues on modern devices.
development
Guide to using Konsta UI for pixel-perfect iOS and Material Design components in Capacitor apps. Works with React, Vue, and Svelte. Use this skill when users want native-looking UI without Ionic, or prefer a lighter framework.
development
Guide to using Ionic Framework components for beautiful native-looking Capacitor apps. Covers component usage, theming, platform-specific styling, and best practices for mobile UI. Use this skill when users need help with Ionic components or mobile UI design.
tools
Guide to accessing device logs on iOS and Android for Capacitor apps. Covers command-line tools, GUI applications, filtering, and real-time streaming. Use this skill when users need to view device logs for debugging.