Skip to content

Using Design System

Ali Sadeghi edited this page Jan 27, 2026 · 5 revisions

Using Design System Skill

Auto-activates when: Working in feature/*/ui/ directories, creating Composables, mentions "UI", "screen", "component"

Design System Enforcement

Ensures X-components are used instead of Material3, preventing design drift.

Component Mappings

// ❌ Material3          // ✅ X-Components
ScaffoldXScaffold
ButtonXButton
OutlinedButtonXOutlinedButton
TextButtonXTextButton
TextXText
TextFieldXTextField
OutlinedTextFieldXOutlinedTextField
CardXCard
IconXIcon
IconButtonXIconButton
SwitchXSwitch
CheckboxXCheckbox
RadioButtonXRadioButton
DividerXDivider
CircularProgressIndicatorXLoadingIndicator

Examples

Creating a Login Form

> Create a login form with email, password, and submit button

AI generates:

@Composable
fun LoginForm(
    email: String,
    password: String,
    onEmailChange: (String) -> Unit,
    onPasswordChange: (String) -> Unit,
    onSubmit: () -> Unit
) {
    Column {
        XTextField(
            value = email,
            onValueChange = onEmailChange,
            label = { XText("Email") }
        )

        XTextField(
            value = password,
            onValueChange = onPasswordChange,
            label = { XText("Password") },
            visualTransformation = PasswordVisualTransformation()
        )

        XButton(
            onClick = onSubmit,
            text = "Login"
        )
    }
}

Creating a Product Card

> Create a product card component with image, title, price, and add to cart button

AI generates using XCard, XText, XButton (not Material3 components)

Theme Usage

// ✅ Correct (in feature modules)
XScaffold {
    // Feature content - NO theme wrapper needed
}

// ❌ Wrong (in feature modules)
XTheme {  // XTheme is app-level only!
    XScaffold { }
}

// ❌ Wrong
MaterialTheme {
    Scaffold { }
}

Note: XTheme is applied at the App level (composeApp). Feature modules should NOT wrap their screens in XTheme.

ScreenRoot Pattern

All screens must follow the ScreenRoot pattern:

// {Feature}Screen - ViewModel wrapper, collects state
@Composable
fun ProductListScreen(
    viewModel: ProductListViewModel = koinViewModel(),
    onProductClick: (String) -> Unit,
    onBackClick: () -> Unit
) {
    val state by viewModel.state.collectAsState()
    ProductListScreenRoot(
        uiState = state,
        onProductClick = onProductClick,
        onBackClick = onBackClick,
        onRetry = viewModel::loadProducts
    )
}

// {Feature}ScreenRoot - ViewModel-independent, takes UiState + callbacks (TESTABLE)
@Composable
fun ProductListScreenRoot(
    uiState: ProductListUiState,
    onProductClick: (String) -> Unit,
    onBackClick: () -> Unit,
    onRetry: () -> Unit
) {
    // UI implementation
}

Key benefits:

  • ScreenRoot is testable without ViewModel mocking
  • Clear separation of concerns
  • UI tests target ScreenRoot with fixture-based UiState

Spec Cross-Reference

When spec exists at .claude/docs/{feature}/spec.md:

  • Validates 4-state pattern matches spec's State Management section
  • Ensures UI flows match spec's Navigation section
  • Verifies all documented callbacks exist in ScreenRoot
  • Reports drift if UI implementation differs from spec

Back to Skills

Clone this wiki locally