Reveal Documentation

repository·main·Indexed 20 days ago

https://github.com/svenjacobs/reveal

A Compose Multiplatform library for creating onboarding tutorials, coach marks, and walkthrough effects across Android, iOS, Desktop, and Web. Reveal allows developers to highlight specific UI elements (Revealables) using a dimmed background overlay and explanatory content. The library provides core functionality via the reveal-core artifact and additional shapes through reveal-shapes.

Tokens
2.8K
Snippets
9
Records
13
Agent score
69%

What's inside Reveal

  1. What is Reveal and its core terminology

    main

    Reveal is a library for creating coach marks, onboarding tutorials, and walkthrough effects in Compose Multiplatform for Android, iOS, Desktop, and Web.

    Key Concepts

    • Revealable: An element on the screen that is highlighted during the effect.
    • Reveal area: The specific area around a Revealable that is highlighted (usually with slight padding).
    • Overlay: The layer that greys out all content except for the Revealable area. It can also host explanatory items (like text or images).
  2. Understand behavioral changes in Reveal v5.0

    main

    Version 5.0 introduces several behavioral changes due to the new popup-based rendering:

    1. Expanded Click Area: Since the overlay is a full-screen popup, onOverlayClick and onRevealableClick will now trigger for clicks anywhere on the screen while the effect is visible, not just within the bounds of the Reveal composable.
    2. OnClick.Passthrough Platform Limits: On Android, OnClick.Passthrough makes the overlay momentarily non-touchable so clicks reach the app below. On iOS, Desktop, and Web, this has no effect because popups always occupy their own input layer and cannot forward touches to layers below.
    3. UI Testing Semantics: UI tests will now see at least two semantics roots when the effect is active (the app root and the popup root).
      • Avoid using composeTestRule.onRoot() as it becomes ambiguous.
      • Use onNodeWithTag(...) or onNodeWithText(...) to query specific nodes across all roots.
      • To assert against the overlay's bounds, use onNodeWithTag("overlay") (the specific hit-test node for the overlay) instead of onRoot().
  3. Remove RevealCanvas and revealCanvasState in v5.0

    main

    When migrating to version 5.0, remove all references to RevealCanvas and its associated state. You no longer need to coordinate multiple Reveal instances via a shared canvas state; each Reveal instance manages its own overlay within its respective window.

    // Before (v4.x)
    @Composable
    fun App() {
        val revealCanvasState = rememberRevealCanvasState()
    
        RevealCanvas(
            modifier = Modifier.fillMaxSize(),
            revealCanvasState = revealCanvasState,
        ) {
            MainScreen(revealCanvasState = revealCanvasState)
        }
    }
    
    @Composable
    fun MainScreen(revealCanvasState: RevealCanvasState) {
        val revealState = rememberRevealState()
    
        Reveal(
            revealCanvasState = revealCanvasState,
            revealState = revealState,
        ) {
            // Contents
        }
    }
    
    // After (v5.0)
    @Composable
    fun App() {
        MainScreen()
    }
    
    @Composable
    fun MainScreen() {
        val revealState = rememberRevealState()
    
        Reveal(
            revealState = revealState,
        ) {
            // Contents
        }
    }
  4. Use Reveal inside Bottom Sheets and Dialogs

    main

    Since the overlay is rendered in a popup attached to the window where Reveal is composed, you can use Reveal inside ModalBottomSheet or Dialog.

    Crucial Requirement: The Reveal instance and its revealable items must be placed inside the sheet or dialog's content. A Reveal instance placed outside a sheet cannot reveal items inside it because they reside in different windows.

    ModalBottomSheet(onDismissRequest = { /* ... */ }) {
        val revealState = rememberRevealState()
    
        Reveal(revealState = revealState) {
            // Sheet contents, revealable via Modifier.revealable(...)
        }
    }
  5. Install Reveal via Maven Central

    main

    Add the reveal-core dependency to your project. The minimum supported Android SDK is 23 (Android 6.0).

    Artifacts

    • reveal-core: Contains the core classes required for using the library.
    • reveal-shapes: Provides additional shapes for explanatory items in the overlay.
    dependencies {
        implementation("com.svenjacobs.reveal:reveal-core:$REVEAL_VERSION")
    }
  6. Migrate from Reveal 4.x to 5.0

    main

    In version 5.0, the rendering model for the reveal overlay has changed. Instead of being hoisted to a RevealCanvas at the top of the Compose hierarchy, Reveal now renders its overlay in a full-screen popup attached to the window it is composed in.

    Key changes:

    • RevealCanvas, RevealCanvasState, and rememberRevealCanvasState() have been removed.
    • The reveal-compat-android artifact is no longer needed and should be removed.
    • The revealCanvasState argument has been removed from the Reveal composable.
    • The reveal effect now correctly renders above ModalBottomSheet and Dialog components, provided the Reveal composable is placed inside the sheet or dialog's content.
  7. Remove reveal-compat-android dependency in v5.0

    main

    The reveal-compat-android artifact and its associated classes (FullscreenRevealOverlayInserter, InPlaceRevealOverlayInserter, RevealOverlayInserter) have been removed. If you were using FullscreenRevealOverlayInserter(revealableOffset = ...) to correct misplaced effects in legacy Android view hierarchies, this is no longer necessary as the offset is now measured automatically.

    dependencies {
        // remove this line
        implementation("com.svenjacobs.reveal:reveal-compat-android:$REVEAL_VERSION")
    }
  8. Implement the Reveal effect in Compose

    main

    To use Reveal, you need to manage a RevealState using rememberRevealState() and wrap your screen content in the Reveal composable.

    Typically, you should have at most one Reveal instance per application screen. Because the overlay is rendered in a full-screen popup, Reveal can be placed anywhere in the Compose hierarchy.

    @Composable
    fun MainScreen() {
        val revealState = rememberRevealState()
    
        // Usually one instance per screen
        Reveal(
            revealState = revealState,
            onRevealableClick = { key -> /* Handle click on revealable area */ },
            onOverlayClick = { key -> /* Handle click on overlay */ },
        ) {
            // Your screen contents go here
        }
    }
  9. Use Reveal inside ModalBottomSheet or Dialog

    main

    Because ModalBottomSheet and Dialog render into their own separate windows, a Reveal composable placed outside of them cannot reveal items inside them. To make Reveal work within these components, you must place the Reveal composable and its RevealState inside the sheet's or dialog's content area.

    ModalBottomSheet(onDismissRequest = { /* ... */ }) {
        val revealState = rememberRevealState()
    
        Reveal(revealState = revealState) {
            // Sheet contents
        }
    }
  10. Fix misplaced Reveal effects

    main
    If you are using version 5 or higher, Reveal automatically measures the offset between the composable hierarchy and the window. This should prevent the reveal effect from being misplaced, even when using a ComposeView nested within a legacy Android view hierarchy. If the effect remains misplaced on version 5+, please file an issue with a reproduction.
  11. Use Reveal inside ModalBottomSheet and Dialog in v5.0

    main

    Because the overlay is now a popup attached to the window, it can render on top of modal components. To ensure the reveal effect works inside a ModalBottomSheet or Dialog, place the Reveal composable and its RevealState inside the content block of the modal component.

    ModalBottomSheet(onDismissRequest = { /* ... */ }) {
        val revealState = rememberRevealState()
    
        Reveal(revealState = revealState) {
            // Sheet contents
        }
    }
  12. Define and launch Revealable items

    main

    To make an element part of the reveal effect, apply the Modifier.revealable(key = ...) modifier to it. You can use any type for the key (e.g., an enum or String). To trigger the effect for a specific item, call revealState.reveal(key).

    enum class Keys { HelloWorld }
    
    // Inside your Reveal block:
    Column {
        Text(
            modifier = Modifier.revealable(key = Keys.HelloWorld),
            text = "Hello world",
        )
    }
    
    // To launch the effect:
    revealState.reveal(Keys.HelloWorld)