Package: portabletext-html
Portable Text HTML Renderer for PythonThis package generates HTML fromPortable Text.For the most part, it mirrorsSanity'sownblock-content-to-htmlNPM library.Installationpip install portabletext-htmlUsageInstantiate thePortableTextRendererclass with your content and call therendermethod.The following contentfromportabletext_htmlimportPortableTextRendererrenderer=PortableTextRenderer({"_key":"R5FvMrjo","_type":"block","children":[{"_key":"cZUQGmh4","_type":"span","marks":["strong"],"text":"A word of"},{"_key":"toaiCqIK","_type":"span","marks":["strong"],"text":" warning;"},{"_key":"gaZingsA","_type":"span","marks":[],"text":" Sanity is addictive."}],"markDefs":[],"style":"normal"})renderer.render()Generates this HTML<p><strong>A word of warning;</strong>Sanity is addictive.</p>Supported typesTheblockandspantypes are supported out of the box.Custom typesBeyond the built-in types, you have the freedom to provide
your own serializers to render any custom_typethe way you
would like to.To illustrate, if you passed this data to the renderer class:fromportabletext_htmlimportPortableTextRendererrenderer=PortableTextRenderer({"_type":"block","_key":"foo","style":"normal","children":[{"_type":"span","text":"Press, "},{"_type":"button","text":"here"},{"_type":"span","text":", now!"}]})renderer.render()The renderer would actually throw an error here, sincebuttondoes not have a corresponding built-in type serializer by default.To render this text you must provide your own serializer, like this:fromportabletext_htmlimportPortableTextRendererdefbutton_serializer(node:dict,context:Optional[Block],list_item:bool):returnf'<button>{node["text"]}</button>'renderer=PortableTextRenderer(...,custom_serializers={'button':button_serializer})output=renderer.render()With the custom serializer provided, the renderer would now successfully
output the following HTML:<p>Press<button>here</button>, now!</p>Supported mark definitionsThe package provides several built-in marker definitions and styles:decorator marker definitionsemstrongcodeunderlinestrike-throughannotation marker definitionslinkcommentCustom mark definitionsLike with custom type serializers, additional serializers for
marker definitions and styles can be passed in like this:fromportabletext_htmlimportPortableTextRendererrenderer=PortableTextRenderer(...,custom_marker_definitions={'em':ComicSansEmphasis})renderer.render()The primary difference between a type serializer and a mark definition serializer
is that the latter uses a class structure, and has three required methods.Here's an example of a custom style, adding an extra font
to the built-in equivalent serializer:fromportabletext_html.marker_definitionsimportMarkerDefinitionclassComicSansEmphasis(MarkerDefinition):tag='em'@classmethoddefrender_prefix(cls,span:Span,marker:str,context:Block)->str:returnf'<{cls.tag}style="font-family: "Comic Sans MS", "Comic Sans", cursive;">'@classmethoddefrender_suffix(cls,span:Span,marker:str,context:Block)->str:returnf'</{cls.tag}>'@classmethoddefrender_text(cls,span:Span,marker:str,context:Block)->str:# custom rendering logic can be placed herereturnstr(span.text)@classmethoddefrender(cls,span:Span,marker:str,context:Block)->str:result=cls.render_prefix(span,marker,context)result+=str(span.text)result+=cls.render_suffix(span,marker,context)returnresultSince therender_suffixandrendermethods here are actually identical to the base class,
they do not need to be specified, and the whole example can be reduced to:fromportabletext_html.marker_definitionsimportMarkerDefinition# basefromportabletext_htmlimportPortableTextRendererclassComicSansEmphasis(MarkerDefinition):tag='em'@classmethoddefrender_prefix(cls,span:Span,marker:str,context:Block)->str:returnf'<{cls.tag}style="font-family: "Comic Sans MS", "Comic Sans", cursive;">'renderer=PortableTextRenderer(...,custom_marker_definitions={'em':ComicSansEmphasis})renderer.render()Supported stylesBlocks can optionally define astyletag. These styles are supported:h1h2h3h4h5h6blockquotenormalMissing featuresFor anyone interested, we would be happy to see a
default built-in serializer for theimagetype added.
In the meantime, users should be able to serialize image types by passing a custom serializer.ContributingContributions are always appreciated 👏For details, see theCONTRIBUTING.md.