---
title: "DroppyKitHostBridge, DroppyKit"
description: "Extension points a host process installs into DroppyKit at launch."
canonical: "https://getdroppy.app/docs/droppykit/api/droppy-kit-host-bridge"
last-updated: "2026-09-09"
---

# DroppyKitHostBridge

Extension points a host process installs into DroppyKit at launch.

`enum DroppyKitHostBridge`

Every extension point is installed through one call, `installHostExtensionPoints(markdownEditorFactory:contextualMarkdownEditorFactory:markdownHighlightPen:)`, and the first call wins. Nothing here has a public setter.

That matters because droplets run in-process with no sandbox. Until DroppyKit 0.3.0 the editor factories were plain `public static var`s, so any loaded droplet could assign one and become the editor Droppy's own Notes surface mounts, for the rest of the session, reading every keystroke the user typed into their notes. Review would probably have caught it; a public SDK should not need review to catch it.

Not behind `@_spi`: `markdownHighlightPen` is a legitimate droplet-facing setting (a droplet's own swatch picker writes it), so the type cannot be host-only in its entirety. Closing the installation point is the part that carries the risk.

## Type properties

### contextualMarkdownEditorFactory

`@MainActor static var contextualMarkdownEditorFactory: ((Binding<String>, DroppyMarkdownEditorContext) -> AnyView)? { get }`

Factory for the real markdown editor surface, carrying the full context (DroppyKit 0.2.2). Droppy installs this at launch.

Read-only. Install it with `installHostExtensionPoints(markdownEditorFactory:contextualMarkdownEditorFactory:markdownHighlightPen:)`.

### isInstalled

`@MainActor static var isInstalled: Bool { get }`

True once a host has installed its extension points.

### isMarkdownHighlightPenInstalled

`@MainActor static var isMarkdownHighlightPenInstalled: Bool { get }`

Whether a host installed real pen storage. `false` means `markdownHighlightPen` reads a default and drops writes, which is the normal state outside Droppy (previews, the harness).

### markdownEditorFactory

`@MainActor static var markdownEditorFactory: ((Binding<String>) -> AnyView)? { get }`

Factory for the real markdown editor surface (the 0.2.0 shape: text only). Kept so bundles and hosts built against 0.2.0/0.2.1 are unaffected; `contextualMarkdownEditorFactory` supersedes it and wins when both are installed.

Read-only. Install it with `installHostExtensionPoints(markdownEditorFactory:contextualMarkdownEditorFactory:markdownHighlightPen:)`.

### markdownHighlightPen

`@MainActor static var markdownHighlightPen: DroppyMarkdownHighlightColor { get set }`

The host's global highlight pen (DroppyKit 0.2.2).

One marker for every document in the app, the host's own editors included: picking a swatch in a droplet recolors Notes and vice versa. That is exactly why it lives here rather than in a droplet's defaults, and why writing it is a sanctioned droplet operation rather than a hijack: a swatch picker is the intended writer.

The *storage* is host-owned and can only be installed once, so a droplet can change the pen but cannot become the pen. Reads fall back to [`yellow`](https://getdroppy.app/docs/droppykit/api/droppy-markdown-highlight-color#yellow) and writes are dropped when no host installed storage; check `isMarkdownHighlightPenInstalled` when you need to tell that apart from a real yellow.

## Type methods

### installHostExtensionPoints(markdownEditorFactory:contextualMarkdownEditorFactory:markdownHighlightPen:)

`@discardableResult @MainActor static func installHostExtensionPoints(markdownEditorFactory: ((Binding<String>) -> AnyView)? = nil, contextualMarkdownEditorFactory: ((Binding<String>, DroppyMarkdownEditorContext) -> AnyView)? = nil, markdownHighlightPen: (get: () -> DroppyMarkdownHighlightColor, set: (DroppyMarkdownHighlightColor) -> Void)? = nil) -> Bool`

Installs the host's extension points. **Host processes only.**

The first call wins and later calls are ignored, so a droplet loaded after launch cannot replace the host's editor or repoint the pen's storage. Hosts must therefore call this once, at launch, before any droplet is loaded and given a chance to mount a wrapped component inside `activate(host:)`.

- Returns: `true` when this call installed the extension points, `false` when they were already installed and nothing changed.
