Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Not just plain text: rendering Markdown in Compose

Not just plain text: rendering Markdown in Compose

Compose offers powerful cross-platform UI development, but lacks a powerful, built-in rich text formatting capabilities. Compose 1.7 introduced support for reading HTML into AnnotatedStrings, but that is only enough for simple runs of formatted text. This leaves developers having to programmatically build more complex AnnotatedStrings, but that is not ideal and it’s pretty much impossible to internationalise.

In the Jewel library we provide a new, powerful API to display Markdown, a common and versatile text format. Markdown is easily created, managed and translated, even allowing you to go beyond what’s achievable with the basic HTML support in Android resources. In fact, Markdown goes beyond inline text styling, and lets you express block-level formatting with facilities like blockquotes, tables, images, and more.

This talk will start by introducing the Jewel library, and then cover all aspects of how we implemented the Jewel Markdown parser. I’ll explain how Markdown is a superior solution compared to HTML for the majority of relevant use cases. We’ll discuss the Markdown specs — or the lack thereof, the various proprietary extensions that exist, and how we’re tackling this challenge. Then, we’ll look at how the library parses the raw Markdown input, and the process that transforms that into a set of Composables on screen. Lastly, the talk will showcase some limitations we’ve run into with the text APIs in Compose, how we’ve worked around some of those, and the impact this work is having on the larger Compose ecosystem.

This talk is aimed at developers who are familiar with Jetpack Compose and/or Compose Multiplatform, and are looking at a way to get rich text rendering, maybe to get rid of a few webviews, or in search of inspiration for their own server-driven UI framework. You’ll not only leave the room with actionable information on those topics but, hopefully, some surprising Markdown facts you didn’t know about!

Sebastiano Poggi

November 30, 2024
Tweet

More Decks by Sebastiano Poggi

Other Decks in Programming

Transcript

  1. “I want to display rich text in this label” —

    You, a fancy cursive-speaking person
  2. Reticulate splines Enable spline reticulation algorithms Learn more “I want

    to display rich text in this label” — You, a fancy cursive-speaking person
  3. Web HTML & CSS Swing HTML & CSS ** Android

    views HTML, to some extent
  4. Web HTML & CSS Swing HTML & CSS ** Android

    views HTML, to some extent Jetpack Compose HTML, to some extent
  5. Web HTML & CSS Swing HTML & CSS ** Android

    views HTML, to some extent Jetpack Compose HTML, to some extent Compose for Desktop Well, err… DIY
  6. Why Markdown Easy to read and write Does not allow

    users to de!ne styling Good for my use case ! Great for UI text and i18n
  7. Why Markdown Easy to read and write Does not allow

    users to de!ne styling Good for my use case ! Great for UI text and i18n
  8. Step 2a: Render block nodes Step 2b: Render inline nodes

    Step 2: Emit UI components inside the composition
  9. Step 2a: Render block nodes Step 2b: Render inline nodes

    inside the composition MarkdownBlocks composables
  10. Blockquote Bullet list Paragraph Header 1 Image Divider Paragraph Code

    block Paragraph … … Simple item Complex item …
  11. Paragraph … Blockquote Complex item Simple item … Bullet list

    Paragraph Header 1 Image Divider Paragraph Code block … render( )
  12. Blockquote Paragraph … Complex item Simple item … Bullet list

    Paragraph Header 1 Image Divider Paragraph Code block … render( )
  13. Blockquote Paragraph … Blockquote Complex item Simple item … Bullet

    list Paragraph Header 1 Image Divider Paragraph Code block … render( )
  14. Blockquote Paragraph Header 1 Image Divider Paragraph Code block …

    Paragraph … Complex item Simple item … Bullet list render( render( )
  15. Blockquote Paragraph Header 1 Image Divider Paragraph Code block …

    Paragraph … Complex item Simple item … Bullet list render( render( )
  16. No HTML. Don’t want to implement a browser May have

    special casing <kbd> <image !# embeds?
  17. Case study: inline code RAW MARKDOWN RENDERED MARKDOWN This PR

    adds animations to the `Onboarding` flow.
  18. Case study: inline code RAW MARKDOWN RENDERED MARKDOWN This PR

    adds animations to the Onboarding "ow. This PR adds animations to the `Onboarding` flow.
  19. Case study: inline code This PR adds animations to the

    `Onboarding` flow. RAW MARKDOWN This PR adds animations to the Onboarding "ow. RENDERED MARKDOWN Onboa &
  20. Case study: inline code This PR adds animations to the

    `Onboarding` flow. RAW MARKDOWN RENDERED MARKDOWN This PR adds animations to the Onboarding "ow. Onboardin '
  21. Case study: inline code I reckon you could improve it

    by using `animateFloatAsState(target, tween(1000, 1500))` ! RAW MARKDOWN RENDERED MARKDOWN I reckon you could improve it by using animateFloatAsState (target, tween(1000, 1500)) ! (
  22. inline images and links Use LinkAnnotation Stateful styling Can’t draw

    focus ring Reticulate splines Enable spline reticulation algorithms Learn more
  23. Two-pass processing: Parse as AST Parse as AST Emit UI

    components Emit UI components Outside the composition Run only when raw Markdown changes
  24. Two-pass processing: Parse as AST Emit UI components Outside the

    composition Run only when raw Markdown changes Inside the composition Run when raw Markdown changes Run when theme changes Run when editor scheme changes Builds AnnotatedStrings: expensive?
  25. Display rich text Render large !le vs many small instances

    lazy container editor mode minimise overhead
  26. Display rich text Render large !le vs many small instances

    lazy container editor mode scroll sync (wip) minimise overhead
  27. Forked by OpenAI for ChatGPT Android A HAT TIP TO

    https://halilibo.com/compose-richtext/ the one from the keynote
  28. Markdown is great Especially for i18n and server-driven UI Try

    out Markdown in Jewel …or make your own renderer