Building Custom Components from Scratch
You can create your own custom components in Anvil entirely in Python. However, if you want more control over the look and function of your custom components, you can build them from scratch using HTML with a Custom HTML Form. You can also style your components using CSS and add functionality using Python or JavaScript.
This page covers building custom components from scratch using a Custom HTML Form. To learn about turning the Form into a custom component, setting its properties and events, and configuring its appearance in the Toolbox, see our general documentation on custom components.
Creating a component from a Custom HTML Form
To create a custom component from scratch, you’ll first want to add a Custom HTML Form from the New Form modal.
Creating a new HTML Form.
From the three dots menu at the top of the Form Editor, tick Use as custom component.
Use a Form as a custom component
Switch to the HTML view to edit the Form’s HTML.
Switch to HTML view
Here you can write HTML to build your custom component. Any valid HTML code you write will show up live in Design view. You can use a combination of native HTML elements and Anvil components.
For more information on using HTML elements in Anvil and styling them with CSS, see Adding HTML Elements.
Accessing elements
You can access your HTML elements from Python code using the dom_nodes API. To do this, you’ll first need to give an element the anvil:dom-node attribute.
<div anvil:dom-node="my-component"></div>Then, in Python, you can look up the element in the Form’s dom_nodes dictionary.
my_element = self.dom_nodes['my-component']These objects are real JavaScript HTMLElement objects, and you can access their properties and methods over Anvil’s Javascript-to-Python bridge. This is especially useful for setting up custom properties and events.
Custom properties using the dom_nodes API
Anvil components have properties that determine how they look and behave. You can create custom properties that control the appearance and content of your HTML elements by:
- Adding the property in the Custom Component Configuration dialog
- Giving the HTML element you want to control an
anvil:dom-nodeattribute - Writing getter and setter methods in Python using the
dom_nodesAPI
For example, the below code creates a custom HTML button. The <span> element inside the button has anvil:dom-node="custom-button-text" as an attribute so that it can be accessed from Python code.
<button class="custom-button" anvil:dom-node="custom-button">
<i class="material-symbols-outlined">check</i>
<span anvil:dom-node="custom-button-text">Click me</span>
</button>We can then add a property called text to change the text of the Button:
Adding a string type property called text in the custom component configuration dialog
Then, we can use Python’s standard Property Descriptors to write getter and setter methods to set the innerText of the custom-button-text element:
@property
def text(self):
return self._text
@text.setter
def text(self, value):
self._text = value
self.dom_nodes['custom-button-text'].innerText = value
Updating the text of the custom button from the Properties Panel
Adding properties to the Object Palette
When you add a property to a custom component, it will show up in the Properties Panel. You can also add some types of properties to the Object Palette.
Boolean type properties
For Boolean type properties, you can choose to have an icon appear in the Object Palette that will toggle that property on and off.
In the Custom Components Configuration dialog, choose the property you want to add to the Object Palette, click “Show advanced settings” and expand the “Designer” section. In the “Designer Hint” dropdown menu, you’ll see several options.
The Designer Hint dropdown in the Custom Component Configuration dialog
Choosing the Designer Hint will add the associated icon to the Object Palette but you’ll still need to write the setter and getter methods. The available icons are:
- enabled:
- font-bold:
- font-italic:
- font-underline:
- toggle:
- visible:
For example, we can add a bold property to our custom button component that controls whether the text on the button is bold or not:
@property
def bold(self):
return self._bold
@bold.setter
def bold(self, value):
self._bold = value
if value:
self.dom_nodes['custom-button-text'].style.fontWeight = "bold"
else:
self.dom_nodes['custom-button-text'].style.fontWeight = "normal" We then can add font-bold as the Designer Hint from the Custom Component Configuration dialog:
We can now toggle the bold property from the Object Palette:
Toggling the bold property of the custom button from the Object Palette
Enum type properties
For enum type properties, there is one Designer Hint option: align-horizontal. If you set a property to have this Designer Hint, up to four icons will be added to the Object Palette depending on what options you add. Below are the icons that will be added if the associated word is one of the enum options:
- : ’left'
- : ‘center’
- : ‘right’
- : ‘justify’ or ‘full’
The align-horizontal Designer Hint added to a property
The align-horizontal icons added to the Object Palette
Just as with the Boolean Designer Hints, you’ll still need to set up the setter and getter methods for the property.
URI type properties
For uri type properties, there is one Designer Hint option, asset-upload, which adds a icon to the Object Palette. Clicking the icon will bring up a window that allows you to choose an asset from your app or to upload a new file.
Custom events
You can also add custom events to your custom components. This section is specifically about using the dom_nodes API to set up custom JavaScript events for HTML components. For more general information about adding custom events to a custom component, see Anvil Docs | Custom Components
Accessing your HTML elements through the dom_nodes dictionary means you can set up event listeners with JavaScript.
For example, we can add a click event to the custom button component. After adding the event in the Custom Component Configuration dialog, we can then add an event listener using Anvil’s Javascript-to-Python bridge to the custom-button element:
class CustomButton(CustomButtonTemplate):
def __init__(self, **properties):
# Set Form properties and Data Bindings.
super().__init__(**properties)
self.dom_nodes['custom-button'].addEventListener('click', self._handle_click)
def _handle_click(self, event):
self.raise_event('click')You can also use anvil:on-dom: to handle native DOM events in HTML. See Handling native DOM events on HTML elements.
When the component is added to another Form, we can now add a click function for it that will run when the button is clicked, just as if it were a normal Anvil Button.
Making a custom component a container
Custom HTML components can be made into containers so that other components can be dragged inside.
To make your custom HTML component a container, you need to tick ‘Make this Form available as a container’ in the Custom Component Configuration dialog.
You’ll also need to add a slot element to your HTML where you want components to be dropped. You’ll be able to drag components into this slot when building the component, but it will also be available to users of the component when it’s added to another Form.
For example, the following code has one slot. Components can be dragged into the slot while editing the custom component and when the custom component is added to another Form.
<div class="custom-container" style="border: 2px solid; padding: 10px;">
<anvil-slot name="default"></anvil-slot>
</div>Do you still have questions?
Our Community Forum is full of helpful information and Anvil experts.