Leveraging @RequireOptIn to create composables that can be used only in previews

Anyone working with Kotlin, especially in the android world, has dealt with RequireOptIn. Actually they had to deal with the consequence of its application which is to explicitly opt-in into using a piece of code that is annotated with it.

@RequiresOptIn

In a nutshell, if you want the consumer of your code to be fully aware that they are about to use it, you annotate the code with RequiresOptIn and that forces the consumer to annotate the call site with OptIn.
Its like informing someone about the dangers of something and then having them sign that you have no responsibilities for anything that might happen to them.

@PreviewOnly

The problem

We have a composable, named renderList, that is part of module A and is being exposed to the rest of the project through another composable, named renderScreen:

// <module A>
// file RenderScreen.kt
@Composable
fun renderScreen(screen: Screen) {
renderTitle(screen.title)
renderList(screen.list)
}
// file RenderTitle.kt
@Composable
internal fun renderTitle(title: Title) {
// rendering the title
}
// file RenderList
@Composable
internal fun renderList(list: List) {
// rendering the list
}
// </module>

renderList knows how to render List instances and we want to preview this rendering but in another module.
Using renderScreen is not possible because it also contains components that cannot be initialized when being in design time.

The solution

We are going to add one more composable in module A which will expose only the renderList:

// <module A>
// file RenderScreen.kt
@PreviewOnly
@Composable
fun renderScreenPreviewer(list: List) {
renderList(screen.list)
}
// </module>

and to prevent its usage in production code we are going to add some friction with the @PreviewOnly annotation which underneath leverages @RequireOptIn:

@RequiresOptIn(
message = "This composable is intended for preview usage only",
level = RequiresOptIn.Level.ERROR
)
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.FUNCTION)
annotation class PreviewOnly
view raw preview-only.kt hosted with ❤ by GitHub

This way every call site of renderScreenPreviewer will end up in a compilation error unless the user explicitly opts in into its usage:

Leave a comment