---
title: CapacitorJS
pagination_prev: demos/static/index
pagination_next: demos/desktop/index
sidebar_position: 5
sidebar_custom_props:
  summary: JS + Web View
---

import current from '/version.js';
import CodeBlock from '@theme/CodeBlock';

The [NodeJS Module](/docs/getting-started/installation/nodejs) can be imported
from the main entrypoint or any script in the project.

The "Complete Example" creates an app that looks like the screenshots below:

<table><thead><tr>
  <th><a href="#demo">iOS</a></th>
  <th><a href="#demo">Android</a></th>
</tr></thead><tbody><tr><td>

![iOS screenshot](pathname:///cap/ios.png)

</td><td>

![Android screenshot](pathname:///cap/and.png)

</td></tr></tbody></table>

:::warning Telemetry

Before starting this demo, manually disable telemetry.  On Linux and MacOS:

```bash
npx @capacitor/cli telemetry off
```

To verify telemetry was disabled:

```bash
npx @capacitor/cli telemetry
```

:::

## Integration Details

This example uses Svelte, but the same principles apply to other frameworks.

#### Reading data

The standard HTML5 File Input element logic works in CapacitorJS:

```html
<script>
import { read, utils } from 'xlsx';

let html = "";

/* show file picker, read file, load table */
async function importFile(evt) {
  // highlight-start
  const f = evt.target.files[0];
  const wb = read(await f.arrayBuffer());
  // highlight-end
  const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
  html = utils.sheet_to_html(ws); // generate HTML and update state
}
</script>

<main>
  <!-- highlight-next-line -->
  <input type="file" on:change={importFile}/>
  <div bind:this={tbl}>{@html html}</div>
</main>
```

#### Writing data

`@capacitor/filesystem` can write Base64 strings:

```html
<script>
import { Filesystem, Directory } from '@capacitor/filesystem';
import { utils, writeXLSX } from 'xlsx';

let html = "";
let tbl;

/* get state data and export to XLSX */
async function exportFile() {
  const elt = tbl.getElementsByTagName("TABLE")[0];
  const wb = utils.table_to_book(elt);
  /* generate Base64 string for Capacitor */
  // highlight-start
  const data = writeXLSX(wb, { type: "base64" });
  await Filesystem.writeFile({
    data,
    path: "SheetJSCap.xlsx",
    directory: Directory.Documents
  }); // write file
  // highlight-end
}

</script>

<main>
  <button on:click={exportFile}>Export XLSX</button>
  <div bind:this={tbl}>{@html html}</div>
</main>
```

## Demo

:::note

This demo was tested on an Intel Mac on 2023 April 01 with Capacitor 4.7.3 and
`@capacitor/filesystem` 4.1.4

The iOS simulator runs iOS 16.2 on an iPhone 14 Pro Max.

The Android simulator runs Android 12.0 (S) API 31 on a Pixel 3.

:::

### Base Project

1) Disable telemetry.

```bash
npx @capacitor/cli telemetry off
```

Verify that telemetry is disabled by running

```bash
npx @capacitor/cli telemetry
```

(it should print `Telemetry is off`)

2) Create a new Svelte project:

```bash
npm create vite@latest sheetjs-cap -- --template svelte
cd sheetjs-cap
```

3) Install dependencies:

<CodeBlock language="bash">{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
npm i --save @capacitor/core @capacitor/cli @capacitor/filesystem`}
</CodeBlock>

4) Create CapacitorJS structure:

```bash
npx cap init sheetjs-cap com.sheetjs.cap --web-dir=dist
npm run build
```

5) Download [`src/App.svelte`](pathname:///cap/App.svelte) and replace:

```bash
curl -o src/App.svelte -L https://docs.sheetjs.com/cap/App.svelte
```

### iOS

6) Follow the [React Native demo](/docs/demos/mobile/reactnative#demo) to
ensure the iOS simulator is ready.

7) Create iOS app

```bash
npm i --save @capacitor/ios
npx cap add ios
```

8) Enable file sharing and make the documents folder visible in the iOS app.
The following lines must be added to `ios/App/App/Info.plist`:

```xml title="ios/App/App/Info.plist"
<plist version="1.0">
<dict>
<!-- highlight-start -->
  <key>UIFileSharingEnabled</key>
  <true/>
  <key>LSSupportsOpeningDocumentsInPlace</key>
  <true/>
<!-- highlight-end -->
  <key>CFBundleDevelopmentRegion</key>
```

(The root element of the document is `plist` and it contains one `dict` child)

9) Run the app in the simulator

```bash
npm run build
npx cap sync
npx cap run ios
```

10) Test the app

Open the app and observe that presidents are listed in the table.

Touch "Export XLSX" and a popup will be displayed.

To see the generated file, switch to the "Files" app in the simulator and look
for `SheetJSCap.xlsx` in "On My iPhone" > "`sheetjs-cap`"

### Android

11) Follow the [React Native demo](/docs/demos/mobile/reactnative#demo) to
ensure the Android simulator is ready.

12) Create Android app

```bash
npm i --save @capacitor/android
npx cap add android
```

13) Enable file reading and writing in the Android app.
The following lines must be added to `android/app/src/main/AndroidManifest.xml`
after the `Permissions` comment:

```xml title="android/app/src/main/AndroidManifest.xml"
    <!-- Permissions -->

<!-- highlight-start -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- highlight-end -->

    <uses-permission android:name="android.permission.INTERNET" />
```

14) Run the app in the simulator

```bash
npm run build
npx cap sync
npx cap run android
```

15) Test the app

Open the app and observe that presidents are listed in the table.

Touch "Export XLSX" and the emulator will ask for permission:

Tap "Allow" and a popup will be displayed with a path.

To see the generated file, switch to the "Files" app in the simulator, tap the
`≡` icon and tap "Documents". Tap "Documents" folder to find `SheetJSCap.xlsx`.