# How to Add New Frontend Components in Palmier Pro: A SwiftUI Guide

> Learn to add new frontend components in Palmier Pro using SwiftUI. Follow our guide to integrate custom views adhering to the AppTheme and design system for seamless development.

- Repository: [Palmier/palmier-pro](https://github.com/palmier-io/palmier-pro)
- Tags: how-to-guide
- Published: 2026-06-21

---

**To add new frontend components in Palmier Pro, create a SwiftUI `View` that uses only `AppTheme` constants for styling, binds state to `EditorViewModel`, and inserts into the existing view hierarchy following the established design system patterns.**

Palmier Pro’s frontend architecture combines SwiftUI with AppKit where low-level control is required. All visual styling lives in a central design system, ensuring consistency across the macOS application. When you add new frontend components, you must respect this structured approach to maintain the app’s unified visual language and interaction patterns.

## Architecture Overview

Palmier Pro implements a layered UI architecture where **SwiftUI** handles the majority of interface elements, with **AppKit** (`NSViewRepresentable`) reserved for specific low-level graphics requirements. The **`AppTheme`** enum in [`Sources/PalmierPro/UI/AppTheme.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Sources/PalmierPro/UI/AppTheme.swift) serves as the single source of truth for all visual attributes—colors, spacing, font sizes, corner radii, and shadows. State management follows a unidirectional pattern where mutable data belongs exclusively in **`EditorViewModel`**, not in individual views.

## Step-by-Step Guide to Adding Frontend Components

### 1. Create the SwiftUI View Component

Begin by creating a new Swift file in the appropriate directory. Define a struct conforming to the `View` protocol. For toolbar elements, place files in the `Toolbar` group; for media panel components, use `MediaPanel`.

```swift
import SwiftUI

struct BookmarksButton: View {
    @Environment(EditorViewModel.self) private var editor
    
    var body: some View {
        // Implementation details below
        EmptyView()
    }
}

```

If you require direct AppKit access—for example, when implementing complex rendering layers—create an `NSViewRepresentable` wrapper instead. Reference [`Sources/PalmierPro/Preview/PreviewView.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Sources/PalmierPro/Preview/PreviewView.swift) for the correct implementation pattern.

### 2. Apply Design System Styling via AppTheme

Never hard-code visual values. Import `AppTheme` and reference its static constants for every attribute:

- **`AppTheme.IconSize`** for width and height dimensions
- **`AppTheme.FontSize`** for type scaling
- **`AppTheme.Text`** for color values (primary, secondary, tertiary)
- **`AppTheme.Accent`** for interactive elements
- **`AppTheme.Spacing`** for layout margins

Apply the **`hoverHighlight()`** modifier to interactive elements, which provides consistent hover feedback across the application.

### 3. Connect State to EditorViewModel

Access shared state through the **`@Environment(EditorViewModel.self)`** property wrapper. This injects the central view model without manual initialization. For toggle actions or panel visibility, bind to Boolean properties on `EditorViewModel`:

```swift
Button(action: { editor.isBookmarksPanelVisible.toggle() }) {
    // Button content
}

```

If the component requires new state fields, add them to `EditorViewModel` following the pattern in `Sources/PalmierPro/Editor/ViewModel/EditorViewModel+AIEdit.swift`, which exposes panel visibility flags.

### 4. Integrate into the View Hierarchy

Insert your component into an existing container. For toolbar additions, modify [`Sources/PalmierPro/Toolbar/ToolbarView.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Sources/PalmierPro/Toolbar/ToolbarView.swift) and add your view to the main `HStack`:

```swift
HStack(spacing: AppTheme.Spacing.md) {
    ExistingButton()
    BookmarksButton()  // Your new component
}

```

For media panel components, integrate into [`Sources/PalmierPro/MediaPanel/MediaTab/FolderTileView.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Sources/PalmierPro/MediaPanel/MediaTab/FolderTileView.swift) or create analogous container views.

### 5. Follow Interaction Patterns

Use **`.buttonStyle(.plain)`** for all buttons to ensure consistent styling with the rest of the interface. Add help text using the `.help()` modifier to support keyboard shortcut discovery. Maintain small, stateless view structs—complex logic belongs in `EditorViewModel` or dedicated extensions.

## Complete Implementation Example

Below is a production-ready implementation of a toolbar button that toggles the Bookmarks panel, following Palmier Pro conventions:

```swift
import SwiftUI

/// A toolbar button that toggles the Bookmarks panel visibility.
struct BookmarksButton: View {
    @Environment(EditorViewModel.self) private var editor

    var body: some View {
        Button(action: { editor.isBookmarksPanelVisible.toggle() }) {
            Image(systemName: "bookmark")
                .font(.system(size: AppTheme.FontSize.md))
                .foregroundStyle(
                    editor.isBookmarksPanelVisible
                        ? AppTheme.Text.primaryColor
                        : AppTheme.Text.tertiaryColor
                )
                .frame(width: AppTheme.IconSize.sm, height: AppTheme.IconSize.sm)
                .hoverHighlight(isActive: editor.isBookmarksPanelVisible)
        }
        .buttonStyle(.plain)
        .help("Show Bookmarks (⌥B)")
    }
}

```

To wire this into the toolbar, edit [`Sources/PalmierPro/Toolbar/ToolbarView.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Sources/PalmierPro/Toolbar/ToolbarView.swift) and insert the component into the existing `HStack` (around line 37):

```swift
HStack(spacing: AppTheme.Spacing.md) {
    // Existing toolbar items...
    BookmarksButton()
}

```

## Key Source Files and Patterns

Reference these implementation files when adding new frontend components:

- **[`Sources/PalmierPro/UI/AppTheme.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Sources/PalmierPro/UI/AppTheme.swift)** – Central design system defining colors, spacing, fonts, and shadows.
- **[`Sources/PalmierPro/Toolbar/ToolbarView.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Sources/PalmierPro/Toolbar/ToolbarView.swift)** – Primary toolbar layout demonstrating container composition.
- **`Sources/PalmierPro/Editor/ViewModel/EditorViewModel+Folders.swift`** – Example of state management patterns for folder-related UI actions.
- **`Sources/PalmierPro/Editor/ViewModel/EditorViewModel+AIEdit.swift`** – Reference for implementing panel visibility toggles and Boolean state flags.
- **[`Sources/PalmierPro/MediaPanel/MediaTab/FolderTileView.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Sources/PalmierPro/MediaPanel/MediaTab/FolderTileView.swift)** – Complex SwiftUI component example following the design system conventions.
- **[`Sources/PalmierPro/Preview/PreviewView.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Sources/PalmierPro/Preview/PreviewView.swift)** – Implementation of `NSViewRepresentable` for embedding AppKit views within SwiftUI.

## Summary

- **Create SwiftUI views** (or `NSViewRepresentable` for AppKit needs) in the appropriate directory group.
- **Use only `AppTheme` constants** for visual styling—never hard-code colors, sizes, or spacing.
- **Bind state via `@Environment(EditorViewModel.self)`** to access shared mutable data and actions.
- **Insert components** into existing containers like [`ToolbarView.swift`](https://github.com/palmier-io/palmier-pro/blob/main/ToolbarView.swift) or media panel hierarchies.
- **Apply standard modifiers** including `.buttonStyle(.plain)` and `hoverHighlight()` for consistent interaction feedback.

## Frequently Asked Questions

### Where should I place new component files in the Palmier Pro repository?

Place new SwiftUI components in `Sources/PalmierPro/` under the appropriate functional group—`Toolbar/` for toolbar elements, `MediaPanel/` for media interface components, or `UI/` for reusable generic elements. Follow the existing file naming convention: `[ComponentName].swift` for views and `[ComponentName]+[Extension].swift` for view modifiers or extensions.

### Can I use AppKit views instead of SwiftUI for frontend components?

Yes, when you require low-level graphics performance or specific AppKit functionality, implement `NSViewRepresentable` to wrap AppKit views. Reference [`Sources/PalmierPro/Preview/PreviewView.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Sources/PalmierPro/Preview/PreviewView.swift) for the correct protocol implementation pattern. However, default to SwiftUI for standard UI elements to maintain consistency with the rest of the application.

### How do I handle user interactions in new components?

Route all user interactions through methods on `EditorViewModel`. Inject the view model using `@Environment(EditorViewModel.self)` rather than passing it through initializers. For button actions, call closures that invoke view model methods. For complex state changes, add properties to `EditorViewModel` following the pattern in `EditorViewModel+Folders.swift`.

### What is the role of EditorViewModel in frontend components?

`EditorViewModel` serves as the single source of truth for mutable application state and business logic. Frontend components remain stateless and declarative, observing `EditorViewModel` properties for display state and calling its methods for actions. This architecture ensures predictable data flow and simplifies testing by decoupling UI from logic.