Skill: Compose UI Components and Screens
SkillDev toolsStructure and routing guide for composeApp screens, components, and their relationships.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Skill: Compose UI Components and Screens skill
What this skill tells your AI
The instructions your AI receives, as published by championswimmer/twofac in .agents/skills/ui-components/SKILL.md and read by ahel’s review.
Use this skill when working on UI in composeApp, especially to decide where to place new screens/components and how they connect.
composeApp UI structure
- Route-level screens live in:
composeApp/src/commonMain/kotlin/tech/arnav/twofac/screens/
- Reusable UI components live in:
composeApp/src/commonMain/kotlin/tech/arnav/twofac/components/<domain>/
- Navigation routes are declared in:
composeApp/src/commonMain/kotlin/tech/arnav/twofac/navigation/NavigationRoutes.kt
- Route wiring is in:
composeApp/src/commonMain/kotlin/tech/arnav/twofac/App.kt
Current component domains:
components/accountscomponents/homecomponents/otpcomponents/securitycomponents/settings
Screens and responsibilities
HomeScreen
- Shows home-state UX:
- loading state
- empty vault state
- locked state
- OTP list when unlocked
- Triggers account loading and unlock flow (including saved passkey auto-unlock).
AccountsScreen
- Shows account list and account-management entry points.
- Handles locked/error/loading branches for account browsing.
- Entry point to add-account and account-detail routes.
AddAccountScreen
- Handles adding accounts by OTP URI.
- Supports camera QR import and clipboard QR import.
- Collects passkey when library is locked.
AccountDetailScreen
- Shows selected account details.
- Generates OTP for selected account.
- Handles account deletion with confirmation dialog.
- Note: this screen currently uses Material primitives directly (no shared
components/*imports).
SettingsScreen
- Manages storage actions, remember/secure unlock, backup import/export, and companion sync.
- Coordinates passkey-gated actions for sensitive operations.
- Delegates platform-specific settings section to
PlatformSettingsContent.
PlatformSettingsContent (expect/actual)
commonMain: expect declaration.desktopMain: tray/menu-bar toggle + quit button card.androidMain,iosMain,wasmJsMain: currently no-op actuals.
Screen → component relationships
-
HomeScreencomponents/home/HomeLoadingStatecomponents/home/HomeEmptyStatecomponents/home/HomeLockedStatecomponents/otp/HomeOtpListSectioncomponents/security/PasskeyDialog
-
AccountsScreencomponents/accounts/AccountsLockedStatecomponents/accounts/AccountsErrorStatecomponents/accounts/AccountsListContentcomponents/security/PasskeyDialog
-
AddAccountScreencomponents/accounts/OtpUriInputFieldcomponents/accounts/QrImportActionscomponents/accounts/AddAccountPasskeyFieldcomponents/accounts/InlineErrorMessage
-
SettingsScreencomponents/settings/StorageLocationCardcomponents/settings/RememberPasskeyCardcomponents/settings/BackupProvidersCardcomponents/settings/CompanionSyncCardcomponents/settings/DeleteStorageDialogcomponents/security/PasskeyDialogscreens/PlatformSettingsContent
-
AccountDetailScreen- No shared components yet (screen-owned UI)
Component nesting relationships
HomeOtpListSection→ rendersOTPCardrows.AccountsListContent→ rendersAccountListItemrows.BackupProvidersCard→ rendersBackupProviderRowrows.
Where to add new components
- Prefer reusable components in
components/<domain>/ComponentName.kt. - Choose domain by feature ownership:
- account management UI →
components/accounts - home states/layouts →
components/home - OTP presentation widgets →
components/otp - auth/passkey dialogs →
components/security - settings cards/rows/dialogs →
components/settings
- account management UI →
- Keep route-specific glue/state logic in screen files; extract only reusable/presentational parts into
components/*. - If you create a new domain, keep naming consistent:
tech.arnav.twofac.components.<domain>.ComponentName.
Where to add new screens
- Add route-level composable in
screens/(e.g.NewFeatureScreen.kt). - Add a typed route to
navigation/NavigationRoutes.ktusing@Serializableobject/data class. - Wire the screen into
App.ktNavHostwith acomposable<...>entry. - If it is top-level navigation, update:
TopLevelDestination- bottom bar selection logic (
shouldShowBottomBar,isSelected)
- Keep platform-specific variants as
expect/actualonly when platform API differences are required.
Quick checklist before finishing UI changes
- Is route-level orchestration in
screens/and reusable UI incomponents/<domain>/? - Are typed routes declared in
NavigationRoutes.kt? - Is
App.ktnavigation wiring updated? - Are component imports domain-consistent and not placed in
componentsroot?
Signals
- GitHub stars
- 125
- Forks
- 8
- Last commit
- Jun 2026
Advanced
- Catalog kind
- skill
- Gateway key
ui-components- Source
- github.com/championswimmer/twofac