Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mahmoud-b28887f9.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

KPDF renders PDF documents through a small set of composables that share a single state holder. To display a PDF you choose a source, build a viewer configuration, create the state with rememberPdfViewerState, and drop KPdfViewer into your layout. The steps below walk through each piece in order.
1

Choose a KPdfSource

KPdfSource describes where the PDF comes from. Pick the variant that matches your data.
// Load from a remote URL (optional auth headers supported)
val source = KPdfSource.Url(
    url = "https://example.com/document.pdf",
    headers = mapOf("Authorization" to "Bearer token"),
)

// Load from raw bytes already in memory
val source = KPdfSource.Bytes(pdfBytes)

// Load from a Base64-encoded string
val source = KPdfSource.Base64(base64String)
Pass this value down to your composable as a stable parameter so the SDK does not reload the document on every recomposition.
2

Create a KPdfViewerConfig with the builder

KPdfViewerConfig controls runtime behavior — zoom limits, gesture toggles, and cache sizes. Build it once inside a remember block so the reference stays stable.
val viewerConfig = remember {
    KPdfViewerConfig.builder()
        .enableZoom(true)
        .enableSwipe(true)
        .zoomRange(minZoom = 1f, maxZoom = 5f)
        .doubleTapZoom(2f)
        .ramCacheSize(6)
        .diskCacheSize(24)
        .preloadPageCount(2)
        .build()
}
Builder optionDescription
enableZoomAllow pinch-to-zoom gestures
enableSwipeAllow swipe-to-navigate gestures
zoomRangeMinimum and maximum zoom factors
doubleTapZoomZoom factor applied on a double tap
ramCacheSizeNumber of pages to keep in RAM
diskCacheSizeNumber of pages to keep on disk
preloadPageCountPages to render ahead of the current page
3

Call rememberPdfViewerState

rememberPdfViewerState creates a KPdfViewerState, opens the document, and binds platform save/open effects for you. Call it at the top of your composable.
val viewerState = rememberPdfViewerState(
    source = stableSource,
    config = viewerConfig,
)
The state is keyed on source and config. Passing a new config object on every recomposition recreates the state and resets all transient flows, including openDocumentState and saveState.
4

Add KPdfViewer to your layout

Place KPdfViewer anywhere in your composable tree. It reads the active page and zoom level directly from KPdfViewerState.
KPdfViewer(
    state = viewerState,
    modifier = Modifier.fillMaxSize(),
)
For a production screen that also includes a toolbar and thumbnail strip, use the complete layout below.
@Composable
fun FullPdfScreen(source: KPdfSource) {
    val viewerState = rememberPdfViewerState(
        source = source,
        config = KPdfViewerConfig.builder()
            .preloadPageCount(1)
            .diskCacheSize(50)
            .build(),
    )
    var thumbnailsVisible by remember { mutableStateOf(true) }
    val scope = rememberCoroutineScope()

    Column(modifier = Modifier.fillMaxSize()) {
        KPdfViewerToolbar(
            state = viewerState,
            isThumbnailStripVisible = thumbnailsVisible,
            onThumbnailToggle = { thumbnailsVisible = it },
            onShareClick = {
                scope.launch {
                    viewerState.exportPdf().onSuccess { bytes ->
                        sharePdfBytes(bytes)
                    }
                }
            },
            modifier = Modifier
                .fillMaxWidth()
                .padding(12.dp),
        )

        KPdfViewer(
            state = viewerState,
            modifier = Modifier
                .fillMaxWidth()
                .weight(1f),
        )

        if (thumbnailsVisible) {
            KPdfThumbnailStrip(
                state = viewerState,
                onPageClick = { pageIndex ->
                    viewerState.goToPage(pageIndex)
                },
                modifier = Modifier
                    .fillMaxWidth()
                    .height(172.dp)
                    .padding(horizontal = 12.dp),
            )
        }
    }
}
Keep source and config stable. If you construct KPdfViewerConfig inline — outside a remember block — Compose recreates it on every recomposition. This causes rememberPdfViewerState to produce a new state instance, which resets openDocumentState, saveState, and other transient flows back to their initial values.