> ## Documentation Index
> Fetch the complete documentation index at: https://mahmoud-b28887f9.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# KPDF quickstart: display your first PDF in minutes

> Go from zero to a working Compose Multiplatform PDF viewer on Android and iOS with four steps: add dependencies, create a source, get viewer state, and render.

This guide walks you through the shortest path to a working PDF viewer. By the end you will have a composable that loads a PDF from any source, renders pages with pinch-to-zoom and swipe navigation, and handles its own lifecycle cleanup.

<Steps>
  <Step title="Add the dependencies">
    Add both KPDF modules to your shared module's `build.gradle.kts`:

    ```kotlin theme={null}
    implementation("com.mahmoud.kpdf:kpdf-core:1.0.0")
    implementation("com.mahmoud.kpdf:kpdf-compose:1.0.0")
    ```

    `kpdf-core` provides the PDF engine and state APIs. `kpdf-compose` provides the Compose viewer components and the platform save/open integrations. You need both for a full viewer.

    See [Installation](/installation) for full Gradle setup details and Groovy DSL equivalents.
  </Step>

  <Step title="Create a KPdfSource">
    Create a `KPdfSource` that tells the SDK where your PDF comes from. KPDF supports URLs, raw bytes, and Base64 strings:

    ```kotlin theme={null}
    // Load from a remote URL
    val source = KPdfSource.Url("https://example.com/document.pdf")

    // Load from bytes you already have
    val source = KPdfSource.Bytes(pdfBytes)

    // Load from a Base64 string or data URL
    val source = KPdfSource.Base64(base64String)
    ```

    For authenticated remote PDFs, pass request headers:

    ```kotlin theme={null}
    val source = KPdfSource.Url(
        url = "https://example.com/secure.pdf",
        headers = mapOf("Authorization" to "Bearer token")
    )
    ```
  </Step>

  <Step title="Call rememberPdfViewerState">
    Inside your composable, call `rememberPdfViewerState` to create and remember the viewer state. Wrap `source` in `remember` and build `KPdfViewerConfig` inside `remember` so neither is reconstructed on every recomposition:

    ```kotlin theme={null}
    val stableSource = remember(source) { source }
    val viewerConfig = remember {
        KPdfViewerConfig.builder()
            .enableSwipe(true)
            .ramCacheSize(6)
            .diskCacheSize(24)
            .preloadPageCount(2)
            .build()
    }

    val viewerState = rememberPdfViewerState(
        source = stableSource,
        config = viewerConfig,
    )
    ```

    <Note>
      Keep `source` and `config` stable with `remember`. If you rebuild `KPdfViewerConfig` inline on every recomposition, `rememberPdfViewerState` recreates the viewer state and transient flows such as `openDocumentState` reset back to `Idle`.
    </Note>
  </Step>

  <Step title="Add KPdfViewer to your layout">
    Pass the viewer state to `KPdfViewer` to render the PDF surface:

    ```kotlin theme={null}
    KPdfViewer(
        state = viewerState,
        modifier = Modifier.fillMaxSize(),
    )
    ```

    `KPdfViewer` reads the active page and zoom level from `KPdfViewerState` and handles swipe navigation and pinch-to-zoom automatically.
  </Step>
</Steps>

## Complete minimal example

Here is the full composable from the steps above assembled together:

```kotlin theme={null}
@Composable
fun PdfScreen(source: KPdfSource) {
    val stableSource = remember(source) { source }
    val viewerConfig = remember {
        KPdfViewerConfig.builder()
            .enableSwipe(true)
            .ramCacheSize(6)
            .diskCacheSize(24)
            .preloadPageCount(2)
            .build()
    }

    val viewerState = rememberPdfViewerState(
        source = stableSource,
        config = viewerConfig,
    )

    KPdfViewer(state = viewerState)
}
```

Pass any `KPdfSource` to `PdfScreen` and the viewer handles loading, rendering, caching, and cleanup when the composable leaves the composition.

## Next steps

Once the basic viewer is working, you can extend it with connected views and platform flows:

* Add `KPdfViewerToolbar` and `KPdfThumbnailStrip` using the same `viewerState` — no extra wiring required.
* Call `viewerState.requestSave()` to let users save the current PDF to their device.
* Call `viewerState.requestOpenFromDevice()` to let users pick a local PDF.
* Call `viewerState.openInExternalApp()` to hand the PDF to another installed app.
* Use `viewerState.exportPdf()` to get raw bytes and feed them into your own share flow.
