Static elements¶
Custom static visual elements are ones that only need to define their HTML output.
These elements are called static because changing a State
variable, even if
bound to an element's property, does not impact the rendering.
Declaring the element¶
To declare a static element, the call to the
Element
constructor must provide the render_xhtml
argument with a function that generates the XHTML fragment that represents
this element.
XHTML vs. HTML
XHTML is a stricter version of HTML that is an XML application. In particular, in XHTML:
- Elements must be properly nested.
- Elements must be properly closed.
- Attribute values must be properly quoted.
Say that you want to create a control that displays a static string that different pages will use over and over. That could, for example, be an application title or a company name.
We are going to create a custom visual element that does just that. This control
will be called "caption", located in a new library called "custom".
In order to create an instance of this control in our Markdown page, we
simply need to write: <|custom.caption|>
in the Markdown text. If we were
to create an HTML page, we would insert the tag: <custom:caption/>
.
Our control is very simple: it just needs to generate the HTML fragment
<span>some text</span>
. So let's put some code that generates this in
the element declaration:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Line 3 introduces our custom element library. We override the two methods that need to be defined:
get_name()
(line 4): we return the name under which this library is identified in the definition of the application pages.get_elements()
(line 7): we create a single custom element called "caption", that has a single (unused) property called "text". This property also happens to be the default property for this control.
Our HTML code for this control is so simple that we could generate it from a lambda function assigned to the render_xhtml argument of the Element constructor (line 13). This might not be possible for more complex controls.
Also, note that this lambda function takes an argument: props. This is a dictionary that reflects the value of each of this control's properties. We will touch on this in a minute.
Our element library is now entirely defined. Let us create a page that uses it:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
When the application is run, the page that is shown displays our control as expected:
Using properties¶
So far, the text content of our control was hard-coded in the element rendering function. A more practical use case is one where the text would reflect the value of a property.
To achieve this, we will use the property value sent to the XHTML rendering function.
Just change the lambda function that we used above to the following code:
render_xhtml=lambda props: f'<span>{props.get("text", "empty")}</span>'
With this implementation, the text content of our control is defined by the content of the
text property of the control.
So we can now change our Markdown text to:
<|Hello|custom.caption|>
<|custom.caption|text=Hello|>
.
Re-running the application will produce the following page content.
Also note that we could have created a variable to store the text:
text="Hello"
And use that variable in the Markdown definition:
<|{text}|custom.caption|>
The result would be strictly equivalent.
After the page is rendered, changing the value of this variable would not impact the control itself.
More complex rendering¶
If the rendering is more complex, then you will certainly need to perform it in a separate function.
We can augment our example by adding another property that will impact the size of the text.
We will create a new property called size that should be set to a string that can be any value among "xs", "s", "l" and "xl". The size of the text should reflect the size property.
Let us improve the definition of our element library to take that into account:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
In this new definition, the property size was added. It is used in the rendering
function, which is now an actual function called render_caption.
In the rendering function for this element (lines 8 to 21), we compute a CSS style
to apply to the span HTML element we create.
If we now replace our control fragment in the Markdown page to:
<|Extra small|custom.caption|size=xs|> <|Small|custom.caption|size=s|>
<|Normal|custom.caption|>
<|Large|custom.caption|size=l|> <|Extra Large|custom.caption|size=xl|>
We can generate the following page that shows our custom control using the two defined properties.