> ## 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.

# KPdfOpenDocumentState: local PDF file picker state

> KPdfOpenDocumentState tracks the file picker lifecycle when users open a local PDF — from picker launch through KPdfSource delivery, cancellation, or error.

`KPdfOpenDocumentState` is a sealed interface that models the full lifecycle of letting a user pick a PDF from their device storage. Collect it from `KPdfViewerState.openDocumentState` (a `StateFlow`) and, on `Success`, pass the returned `KPdfSource` directly to `viewerState.open()` to load the chosen file. Trigger the picker by calling `viewerState.requestOpenFromDevice()`. The state resets to `Idle` when a new request is initiated.

## Variants

<ResponseField name="Idle" type="data object">
  No picker session is in progress. This is the initial state and the state after a terminal event (`Success`, `Cancelled`, or `Error`) has been handled and the next request starts.
</ResponseField>

<ResponseField name="AwaitingSelection" type="data class">
  The platform file picker is open and waiting for the user to select a file.

  <ResponseField name="requestId" type="Long" required>
    Unique identifier for this open request. Use it to correlate picker events when your UI logic needs to distinguish between multiple requests.
  </ResponseField>

  <ResponseField name="mimeTypes" type="List<String>" required>
    The MIME type filter list passed to the platform picker, typically `["application/pdf"]`. The picker shows only files matching these types.
  </ResponseField>
</ResponseField>

<ResponseField name="Success" type="data class">
  The user selected a file and the SDK has wrapped it in a `KPdfSource` ready for opening.

  <ResponseField name="source" type="KPdfSource" required>
    A `KPdfSource` instance representing the chosen file. Pass this value to `viewerState.open(source)` to replace the current document.
  </ResponseField>
</ResponseField>

<ResponseField name="Cancelled" type="data object">
  The user dismissed the picker without selecting a file. The current document remains open and unchanged.
</ResponseField>

<ResponseField name="Error" type="data class">
  The picker session failed or the SDK was unable to create a `KPdfSource` from the selected file.

  <ResponseField name="reason" type="KPdfError" required>
    A sealed `KPdfError` value describing the failure. Inspect `reason.message` to get a human-readable explanation.
  </ResponseField>
</ResponseField>

## Handling a successful picker result in Compose

Use a `LaunchedEffect` keyed on `openDocumentState` to call `viewerState.open()` as soon as the user's selection arrives. Pair it with a `Button` that calls `requestOpenFromDevice()` to launch the picker.

```kotlin theme={null}
@Composable
fun OpenFromDeviceButton(viewerState: KPdfViewerState) {
    val openState by viewerState.openDocumentState.collectAsState()

    // React to a successful pick
    LaunchedEffect(openState) {
        val selectedSource = (openState as? KPdfOpenDocumentState.Success)?.source
            ?: return@LaunchedEffect

        viewerState.open(selectedSource)
    }

    // Trigger the picker
    Button(onClick = { viewerState.requestOpenFromDevice() }) {
        Text("Open Local PDF")
    }

    // Optional: surface picker status to the user
    when (openState) {
        KPdfOpenDocumentState.Idle -> Unit

        is KPdfOpenDocumentState.AwaitingSelection -> {
            Text("Choose a PDF file…")
        }

        is KPdfOpenDocumentState.Success -> {
            // LaunchedEffect above handles the open call;
            // you can show a brief "Opening…" indicator here.
            Text("Opening selected file…")
        }

        KPdfOpenDocumentState.Cancelled -> {
            Text("No file selected.")
        }

        is KPdfOpenDocumentState.Error -> {
            val error = (openState as KPdfOpenDocumentState.Error).reason
            Text("Could not open file: ${error.message}")
        }
    }
}
```

## Notes

* `KPdfViewerState.openDocumentState` is a `StateFlow<KPdfOpenDocumentState>`, so it is safe to collect from any composable without suspension on the first frame.
  * If you use `rememberPdfViewerState`, the native file-picker result callback is already wired automatically. You do not need to register any platform callbacks yourself.
* If `openDocumentState` never advances past `Idle` after calling `requestOpenFromDevice()`, the most common cause is an unstable `KPdfViewerConfig` being rebuilt on every recomposition, which recreates the `KPdfViewerState` and clears the in-flight request. Wrap your config in a top-level `remember` block as shown in the [`rememberPdfViewerState`](/api/remember-pdf-viewer-state) reference.
* After calling `viewerState.open(selectedSource)`, `loadState` transitions through `Loading` → `Ready` (or `Error`). You can observe both flows simultaneously.
