Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Both packages support Ionic 8.8.1 or later within Ionic 8 or 9. Native UI requir

## Explore further

- [iPhone Duo layout](packages/theme-ios27/docs/iphone-duo.md) · [Vertical Bars with an existing theme](packages/capacitor-native-ui/docs/ionic-vertical-bars.md).
- [Device layout and posture](packages/theme-ios27/docs/vertical-bars-layout.md) · [Vertical Bars with an existing theme](packages/capacitor-native-ui/docs/ionic-vertical-bars.md).
- [Theme migration](packages/theme-ios27/docs/migration.md) · [Native UI migration](packages/capacitor-native-ui/docs/migration.md).

Use standard native buttons without Ionic through the [plain HTML adapter](packages/capacitor-native-ui/docs/framework-independent.md), or keep Ionic markup and enable only [Vertical Bars](packages/capacitor-native-ui/docs/configuration.md). Both use the same native renderers.
Expand Down
2 changes: 1 addition & 1 deletion demo/src/app/docs/docs-content.generated.ts

Large diffs are not rendered by default.

10 changes: 6 additions & 4 deletions packages/capacitor-native-ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,21 @@ Projection changes presentation; it does not translate arbitrary HTML or CSS int

## Install from npm

Install in your Capacitor 8 application:
We use [Capacitor Foldable](https://github.com/erkamyaman/capacitor-foldable), an excellent community plugin by Erkam Yaman, as our standard device-layout integration. It exposes fold state, hinge geometry, bar placement and change events to your application, giving you control over how the layout responds. Foldable handles device reporting; the theme provides Web layout helpers and Native UI projects controls. Install it alongside the package you use, then connect its events in your app.

Install Native UI and Foldable together in your Capacitor application:

```sh
npm install @rdlabo/capacitor-native-ui
npm install @rdlabo/capacitor-native-ui @erkamyaman/capacitor-foldable
```

If you also use the iOS 27 theme, install or update both packages together:

```sh
npm install @rdlabo/capacitor-native-ui @rdlabo/ionic-theme-ios27
npm install @rdlabo/capacitor-native-ui @rdlabo/ionic-theme-ios27 @erkamyaman/capacitor-foldable
```

Both packages share the same release version. Declare Native UI as a direct dependency so Capacitor can discover the plugin. Theme-only apps can install just the theme; its dependency is resolved by npm and does not activate native controls.
The theme and Native UI share the same release version; Foldable is versioned independently. Declare Native UI as a direct dependency so Capacitor can discover the plugin. The setup commands install Foldable as a separate application dependency. Installing these packages does not activate native controls; application startup chooses projection and connects device layout.

Continue with [Ionic setup](docs/setup.md), [HTML setup](docs/framework-independent.md), or [extensions](docs/native-ui-extensions.md). After configuring startup, build your application's Web assets, run `npx cap sync` and rebuild the native app. No repository checkout or archive download is needed.

Expand Down
32 changes: 23 additions & 9 deletions packages/capacitor-native-ui/docs/framework-independent.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,18 @@ Use a Capacitor 8 app with an iOS project, Xcode 26+, and an iOS 26+ device or s

Start with [how projection works](../README.md#how-projection-works): the HTML element remains the source while native controls or Web proxies provide its presentation.

**Want only Vertical Bars?** Follow steps 1–2 to install and mark your HTML buttons, then use the [Web rail configuration](#optional-web-rail) in place of step 3. Remove explicit markers from buttons you want to leave on the Web. Style the rail host in your application and build with step 4 for iOS. You do not need Ionic, `@rdlabo/ionic-theme-ios27`, or `vertical-bars.css`.
**Want only Vertical Bars?** Follow the [device placement setup](#device-placement-for-vertical-bars), alongside steps 1–4 below. Reuse the step 3 runtime without a fixed placement preference. Remove explicit markers from buttons you want to leave on the Web. You do not need Ionic, `@rdlabo/ionic-theme-ios27`, or `vertical-bars.css`.

For Vertical Bars in an app using `ion-tabs`, `ion-toolbar` or other Ionic components with a custom theme, use the [Ionic Vertical Bars setup](ionic-vertical-bars.md#try-it-in-your-existing-ionic-app) instead. The framework (Angular, React or Vue) alone does not determine which adapter to use.

## 1. Install the plugin

Keep your existing Capacitor 8 installation and add the plugin directly:
[Capacitor Foldable](https://github.com/erkamyaman/capacitor-foldable) is our standard integration for device state. Its placement and posture APIs let your app control how the layout adapts; installing it is followed by connecting its initial values and change events.

Keep your existing Capacitor installation and add Native UI and Foldable together:

```sh
npm install @rdlabo/capacitor-native-ui
npm install @rdlabo/capacitor-native-ui @erkamyaman/capacitor-foldable
```

The `/core` entry requires `@capacitor/core` but no Ionic dependencies. If this is currently a browser-only application, configure its Capacitor 8 iOS project before running native controls.
Expand Down Expand Up @@ -70,15 +72,29 @@ For a custom HTML theme, declare `color-scheme: light` or `color-scheme: dark` i

## 4. Build and run on iOS

Build your Web app, run `npx cap sync ios`, and launch the iOS project from Xcode. With the step 3 configuration, Add renders natively and invokes its original click handler. With the rail configuration below, Add retains native element placement and Back uses the native rail when available. In a browser, the same button remains an ordinary Web button. Unmarked HTML remains unchanged.
Build your Web app, run `npx cap sync ios`, and launch the iOS project from Xcode. With the step 3 configuration, Add renders at its source position and invokes its original click handler. Back requests the device-reported native rail when available; connect the device placement below to keep Web spacing in sync. In a browser, the same button remains an ordinary Web button. Unmarked HTML remains unchanged.

If a button stays on the Web on supported iOS, check that it is visible within the configured root, has an accessible name, and that the direct plugin dependency was synced and the iOS app rebuilt.

In an app that also uses Ionic, set `ionic: { auto: false }` to project only explicit sources and registered extensions. See [selective Ionic projection](configuration.md#select-controls-explicitly-in-a-customized-ionic-app).

## Optional Web rail
## Device placement for Vertical Bars

Foldable is already included in the standard installation in step 1. Connect it to your application layout as follows.

Reuse the runtime from step 3 **without `verticalBars.placement`**. Native UI then follows the device-reported edge; a fixed `edge: 'trailing'` would constrain it and can reject a device's leading rail.

Follow [Foldable integration](vertical-bars.md#with-application-owned-css-or-without-ionic):

For a Web fallback rail, use this instead of the startup call in step 3. Call once after both the source root and rail host are mounted; call `await shell.destroy()` when their owner is disposed. Do not start a second shell:
1. Subscribe to `barPlacementChange`, then read `getBarPlacement()` for the initial edge and inset.
2. Apply the edge and inset to your application's CSS. On a null edge, restore ordinary spacing and call `shell.disableVerticalControlArea()`; when an edge returns, call `shell.enableVerticalControlArea()`. Serialize these changes with layout updates.
3. At teardown, remove the listener and destroy the runtime owned by this application.

Keep the explicit source markers from step 2; they declare the controls and their requested placement. To project only Back, remove `data-native-ui="button"` from Add. `controls` does not disable explicit declarations. Without a Web rail host, unavailable native rail controls stay at their original Web positions. The theme package is not required.

## Optional browser rail preview

For a browser-only layout preview, temporarily use this fixed Web rail instead of the startup call in step 3 and the device subscription. Do not copy the fixed placement into the standard device setup. Call once after the source root and host are mounted, and call `await shell.destroy()` when their owner is disposed:

```ts
import { enableNativeUI } from '@rdlabo/capacitor-native-ui/core';
Expand All @@ -96,12 +112,10 @@ const shell = await enableNativeUI({

The plugin uses device-reported rail availability and resolves leading/trailing through the document direction. A placement preference never forces an unsupported system rail. Native rejection restores Web presentation. With `webHost`, explicitly rail-marked HTML controls have Web proxies when native projection is unavailable. Without it, their originals remain visible. The application styles and positions the host and reserves any content spacing. The host must be outside the source root.

Explicit markup chooses placement: Back goes to the rail and Add keeps native element placement. To project only Back, remove `data-native-ui="button"` from Add. `controls` does not disable explicit source declarations. To change rail use later, call `await shell.disableVerticalControlArea()` or `await shell.enableVerticalControlArea()`. Disabling restores original rail controls and removes Web rail proxies without destroying ordinary native projection.
Explicit markup chooses placement: Back goes to the preview rail and Add stays at its original position. Disabling rail projection restores original rail controls and removes Web proxies without destroying ordinary native projection. Before building for a device, restore the step 3 runtime and the Foldable subscription above.

Currently the HTML adapter supports buttons and back buttons. Arbitrary HTML tabs, segments, searchbars and FAB structures are not translated. Ionic adapters continue to support their existing controls. Custom element extensions work with the same scoped root; the existing `tab-accessory` extension placement still requires an Ionic tab-bar owner.

For device-driven spacing and placement, see [Use with Capacitor Foldable](vertical-bars.md#use-with-capacitor-foldable). Read its initial placement and subscribe to changes, applying the edge and inset to your own CSS; the theme package is not required.

## Example

The [plain HTML example](https://github.com/rdlabo-dev/ionic-theme-ios27/tree/main/examples/native-ui-html) demonstrates Add, routerless Home/Details/Back navigation, optional Web rail projection and cleanup. It uses no Ionic or theme CSS.
Loading
Loading