{"slug": "a-lightweight-rich-text-component-without-a-web-view", "title": "A Lightweight Rich Text Component Without a Web View", "summary": "Codename One's PR #5421 introduces RichTextComponent, a lightweight read-only component for formatted text that supports headings, inline styles, lists, links, and images without embedding a web view. The component measures wrapped runs to fit naturally in Codename One layouts, and RichTextArea now imports and exports HTML, Markdown, AsciiDoc, and RTF through direct model adapters.", "body_md": "[PR #5421](https://github.com/codenameone/CodenameOne/pull/5421) adds `RichTextComponent`\n\n, a read-only component for formatted application text. It supports headings, inline styles, lists, links, and images without embedding a web view.\n\n**What is Codename One?** Codename One is an open-source framework for building native iOS, Android, desktop, and web apps from a single Java or Kotlin codebase. Learn more at [codenameone.com](https://www.codenameone.com/).\n\nA `SpanLabel`\n\napplies one style to wrapped text. A `BrowserComponent`\n\nrenders a complete web page. `RichTextComponent`\n\ncovers formatted document content between those two cases and participates in ordinary Codename One layout.\n\nA common screen mixes formatted text with buttons, images, forms, and other Codename One components inside one scrollable container. A `BrowserComponent`\n\nis a poor fit for that layout because it owns a rectangular native surface and its own page viewport. The browser's document height does not naturally become the height of a child inside the parent Codename One layout.\n\n`RichTextComponent`\n\nmeasures wrapped runs for the width it receives and reports the corresponding height. In the default `SizeMode.SHRINK`\n\n, it behaves like a `SpanLabel`\n\n: the parent container scrolls the rich text together with the surrounding components. `SizeMode.SCROLL`\n\nis available when the rich text should keep an assigned height and scroll its own content.\n\nThe read-only view and editor agree on paragraph attributes, inline styles, links, image runs, and wrapping because they do not maintain competing renderers.\n\nHTML is not the only input:\n\n```\nRichTextComponent view = new RichTextComponent();\n\nview.setMarkdown(\"# Trip summary\\n\\n\"\n        + \"Departs **09:40**, arrives *11:15*. \"\n        + \"See the [itinerary](app://itinerary).\\n\\n\"\n        + \"- Window seat\\n\"\n        + \"- Carry-on only\");\n\nform.add(view);\n```\n\n`setContent(...)`\n\naccepts `RichTextFormat.HTML`\n\n, `MARKDOWN`\n\n, `ASCIIDOC`\n\n, or `RTF`\n\n. The model covers headings, emphasis, inline code, links, images, lists, quotes, literal blocks, paragraph alignment, indentation, foreground colors, and highlights.\n\nYou can also assemble content without markup:\n\n```\nRichTextComponent status = new RichTextComponent();\nstatus.append(\"Status: \", TextStyle.DEFAULT)\n      .append(\"confirmed\",\n              TextStyle.DEFAULT\n                      .withBold(true)\n                      .withForeColor(0x1a7f37));\n```\n\nThis path is useful when the content already arrives as structured application data. It avoids generating markup only to parse it again.\n\nA link target does not automatically leave the application:\n\n``` php\nview.addLinkListener(e ->\n        Display.getInstance().execute((String) e.getSource()));\n```\n\nThe event source is the target string. An `https:`\n\nURL can open a browser. An `app:`\n\ntarget can navigate to another form. The application owns the policy.\n\nImages follow the same rule:\n\n``` php\nview.setImageResolver(src -> imageCache.get(src));\n```\n\nThe component does not create a second network stack or choose a cache lifetime. The resolver returns the image for a source string, or `null`\n\nfor a placeholder. That keeps loading, authentication, and caching in application code.\n\n`RichTextArea`\n\nnow imports and exports HTML, Markdown, AsciiDoc, and a practical RTF subset through direct model adapters. Markdown and AsciiDoc do not convert through HTML first.\n\n```\nRichTextArea editor = new RichTextArea();\neditor.setContent(\n        \"# Release notes\\n\\nThis is **ready**.\",\n        RichTextFormat.MARKDOWN);\neditor.insertContent(\n        \"{\\\\rtf1\\\\ansi {\\\\i pasted notes}}\",\n        RichTextFormat.RTF);\neditor.insertContent(\n        \"== Details\\n\\n* Portable\\n* Lightweight\",\n        RichTextFormat.ASCIIDOC);\n```\n\nEditing and reading the same format returns canonical output for that format. It preserves supported meaning, not the original whitespace, tag aliases, or attribute order.\n\nRich clipboard data uses the same negotiation. A copy can publish plain text, HTML, RTF, Markdown, and AsciiDoc together. The receiving component chooses the richest format it understands. Ports with only a plain-text system clipboard still keep the richer payload for transfers inside the application.\n\nThe HTML importer does not execute scripts. It supports the markup that maps to the lightweight document model. It does not implement a CSS cascade, arbitrary DOM layout, forms, video, or embedded JavaScript.\n\n| Content and layout |\n`Label` / `SpanLabel`\n|\n`RichTextComponent` |\n`BrowserComponent` |\n|---|---|---|---|\n| Simple text | ✓ Best fit | Works, but unnecessary | Works, but adds a browser |\n| Mixed with other Codename One content | ✓ | ✓ | Separate browser surface |\n| Child of a scrollable Codename One container | ✓ Participates in parent layout | ✓ Measures its content and participates in parent layout | Owns a separate viewport and scrolling surface |\n| Simple HTML or formatted document content | Convert to plain or uniformly styled text | ✓ HTML, Markdown, AsciiDoc, and RTF | ✓ HTML |\n| Complex HTML, CSS, forms, video, or JavaScript | ✓ |\n\nUse `RichTextArea`\n\ninstead when the formatted document must be editable.\n\nValidate link targets and image sources as application data. A script-free importer prevents script execution; it does not make an untrusted URL safe to open.\n\nThe June editor implementation used a web view by default. The editor and a read-only Codename One rendering could therefore disagree on wrapping, font metrics, or supported markup.\n\nThe new path keeps editing and display on the same model and `RichRunPainter`\n\n. A note can move from `RichTextArea`\n\nto `RichTextComponent`\n\nwithout crossing a browser serialization and rendering boundary.\n\n[Yesterday's post](https://www.codenameone.com/blog/text-input-without-native-overlay/) described the operating system sending text operations into a portable document. `RichTextComponent`\n\ndisplays the same document model with the same painter and no editing session.\n\nTry it where you currently use a `BrowserComponent`\n\nonly to show formatted application text. Keep the browser for pages that are actually web content.\n\nThe last post in this week's series covers [compact strings in ParparVM](https://www.codenameone.com/blog/compact-strings-parparvm/). You can also start with [free and local JavaScript builds](https://www.codenameone.com/blog/javascript-free-open-source/), [calendar synchronization](https://www.codenameone.com/blog/calendar-is-not-add-event/), [Bluetooth support](https://www.codenameone.com/blog/bluetooth-beyond-ble/), or [pure Codename One text editing](https://www.codenameone.com/blog/text-input-without-native-overlay/).", "url": "https://wpnews.pro/news/a-lightweight-rich-text-component-without-a-web-view", "canonical_source": "https://dev.to/codenameone/a-lightweight-rich-text-component-without-a-web-view-3ch0", "published_at": "2026-08-04 15:30:13+00:00", "updated_at": "2026-08-04 15:50:09.947250+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["Codename One", "RichTextComponent", "RichTextArea"], "alternates": {"html": "https://wpnews.pro/news/a-lightweight-rich-text-component-without-a-web-view", "markdown": "https://wpnews.pro/news/a-lightweight-rich-text-component-without-a-web-view.md", "text": "https://wpnews.pro/news/a-lightweight-rich-text-component-without-a-web-view.txt", "jsonld": "https://wpnews.pro/news/a-lightweight-rich-text-component-without-a-web-view.jsonld"}}