Skip to content

TkxRichTextDisplay

import { TkxRichTextDisplay } from 'tekivex-ui';
const blocks = [
{ type: 'heading', level: 2, text: 'Welcome' },
{ type: 'paragraph', text: 'This is the first paragraph with **bold** spans.' },
{ type: 'list', ordered: false, items: ['One', 'Two', 'Three'] },
{ type: 'quote', text: 'A pithy quotation.', cite: 'Anonymous' },
{ type: 'code', language: 'tsx', text: 'const hello = "world";' },
];
<TkxRichTextDisplay blocks={blocks} />

Block schemas are easier to validate, sanitise, and version than HTML. Every block has a known type, and only known types render. Unknown types are silently dropped — there’s no escape hatch for embedding raw HTML, which means no XSS surface.

Use this for content that comes from a CMS, database, or LLM output where you want strict control over what can render.

TypeFields
paragraphtext
headinglevel (1–6), text
listordered, items[]
quotetext, cite?
codelanguage?, text
imagesrc, alt, caption?
divider(no fields)
embedprovider (‘youtube’ | ‘vimeo’ | ‘codepen’), id

paragraph / heading / quote text fields support a tiny inline syntax:

  • **bold**<strong>
  • *italic*<em>
  • `code`<code>
  • [label](url)<a> (URL passes through sanitizeHref())

That’s it. No HTML, no Markdown extensions, no image inlining.

{ type: 'embed', provider: 'youtube', id: 'dQw4w9WgXcQ' }

Renders an <iframe> only for the listed providers, with a strict CSP sandbox attribute. Other providers render as a fallback link.

  • Container: <article> with localised aria-label (e.g. “Rich text content” → “حتوى نص منسق” in Arabic)
  • Headings keep semantic levels — page authors are responsible for ensuring level order makes sense
  • image blocks require non-empty alt (errors at runtime if missing)
  • code blocks render as <pre><code> with no syntax highlighting fallback (fully readable to screen readers)
PropTypeRequiredDescription
blocksRichTextBlock[]yesArray of block objects.
classNamestring
styleCSSProperties

src/components/TkxRichTextDisplay.tsx