Concepts
Rendering
7min
one of the best parts of slate is that it's built with react, so it fits right into your existing application it doesn't re invent its own view layer that you have to learn it tries to keep everything as react y as possible to that end, slate gives you control over the rendering behavior of your custom nodes and properties in your richtext domain you can define these behaviors by passing "render props" to the top level \<editable> component for example if you wanted to render custom element components, you'd pass in the renderelement prop import { createeditor } from 'slate' import { slate, editable, withreact } from 'slate react' const myeditor = () => { const editor = usememo(() => withreact(createeditor()), \[]) const renderelement = usecallback(({ attributes, children, element }) => { switch (element type) { case 'quote' return \<blockquote { attributes}>{children}\</blockquote> case 'link' return ( \<a { attributes} href={element url}> {children} \</a> ) default return \<p { attributes}>{children}\</p> } }, \[]) return ( \<slate editor={editor}> \<editable renderelement={renderelement} /> \</slate> ) } π€ be sure to mix in props attributes and render props children in your custom components! the attributes must be added to the top level dom element inside the component, as they are required for slate's dom helper functions to work and the children are the actual text content of your document which slate manages for you automatically you don't have to use simple html elements, you can use your own custom react components too const renderelement = usecallback(props => { switch (props element type) { case 'quote' return \<quoteelement { props} /> case 'link' return \<linkelement { props} /> default return \<defaultelement { props} /> } }, \[]) leaves when text level formatting is rendered, the characters are grouped into "leaves" of text that each contain the same formatting applied to them to customize the rendering of each leaf, you use a custom renderleaf prop const renderleaf = usecallback(({ attributes, children, leaf }) => { return ( \<span { attributes} style={{ fontweight leaf bold ? 'bold' 'normal', fontstyle leaf italic ? 'italic' 'normal', }} \> {children} \</span> ) }, \[]) notice though how we've handled it slightly differently than renderelement since text formatting tends to be fairly simple, we've opted to ditch the switch statement and just toggle on/off a few styles instead (but there's nothing preventing you from using custom components if you'd like!) one disadvantage of text level formatting is that you cannot guarantee that any given format is "contiguous"βmeaning that it stays as a single leaf this limitation with respect to leaves is similar to the dom, where this is invalid \<em>t\<strong>e\</em>x\</strong>t because the elements in the above example do not properly close themselves they are invalid instead, you would write the above html as follows \<em>t\</em>\<strong>\<em>e\</em>x\</strong>t if you happened to add another overlapping section of \<strike> to that text, you might have to rearrange the closing tags yet again rendering leaves in slate is similarβyou can't guarantee that even though a word has one type of formatting applied to it that that leaf will be contiguous, because it depends on how it overlaps with other formatting of course, this leaf stuff sounds pretty complex but, you do not have to think about it much, as long as you use text level formatting and element level formatting for their intended purposes text properties are for non contiguous , character level formatting element properties are for contiguous , semantic elements in the document decorations decorations are another type of text level formatting they are similar to regular old custom properties, except each one applies to a range of the document instead of being associated with a given text node however, decorations are computed at render time based on the content itself this is helpful for dynamic formatting like syntax highlighting or search keywords, where changes to the content (or some external data) has the potential to change the formatting decorations are different from marks in that they are not stored on editor state toolbars, menus, overlays, and more! in addition to controlling the rendering of nodes inside slate, you can also retrieve the current editor context from inside other components using the useslate hook that way other components can execute commands, query the editor state, or anything else a common use case for this is rendering a toolbar with formatting buttons that are highlighted based on the current selection const myeditor = () => { const editor = usememo(() => withreact(createeditor()), \[]) return ( \<slate editor={editor}> \<toolbar /> \<editable /> \</slate> ) } const toolbar = () => { const editor = useslate() return ( \<div> \<button active={isboldactive(editor)}>b\</button> \<button active={isitalicactive(editor)}>i\</button> \</div> ) } because the \<toolbar> uses the useslate hook to retrieve the context, it will re render whenever the editor changes, so that the active state of the buttons stays in sync
π€
Have a question?
Our super-smart AI,knowledgeable support team and an awesome community will get you an answer in a flash.
To ask a question or participate in discussions, you'll need to authenticate first.