Live Chat

We'll need to share your messages (and your email address if you're logged in) with our live chat provider, Drift. Here's their privacy policy.

If you don't want to do this, you can email us instead at contact@anvil.works.

Anvil Components

The Anvil User Interface is made up of components. Even Forms are a special kind of component.

Some components display information to the user, such as Labels and Images. Others take user input, such as TextBoxes and Buttons.

You control the content, appearance and behaviour of your components by setting their Properties. You can set these properties while you’re building your app using the Properties Panel. You can also set them while the app is running using Python code.

You can make components interactive using Events. These are Python functions that run when something happens - when the user clicks on the component, or enters text, or when the component appears on the screen for the first time.

Many components can contain other components - these are called ‘containers’. Containers can contain other containers, allowing nested structures. This is how Anvil User Interfaces get their structure.

Building UIs in Anvil consists of combining components, properties, events and containers to get the result you want. Let’s look at each concept in more detail.

Components

Components are the things you add to your Form to build your UI. These include Buttons, Labels, TextBoxes and similar widgets.

The entire list of Anvil components is given in this section of the docs. The categories are:

  • Basic Components - things like Labels, Links and Images.
  • Containers - these group components together and define where they sit on the page.
  • RepeatingPanels - these repeat the same group of components for all items in a given list.
  • Forms - these are special containers that appear in the App Browser and can and play the role of a ‘page’ in Anvil.
  • Data Grids - these are an easy and powerful way to create a paginated table.
  • Plots - these display data using Plotly.
  • Maps - Google Maps in Python.
  • Canvas - these provide area where you can draw graphics, like an HTML canvas but in Python.

When you design a Form in the Form editor, you place components on the Form by dragging and dropping them. Anvil stores that layout in the configuration for your app, and knows to create those components at runtime when that particular Form is displayed.

Every component is available in Python as an attribute of the Form object. So when you add a Button to your Form in the designer and give it the name button_1:

The Design View with a single button that says 'button_1' on it, showing the Properties Panel where the name is 'self.button_1'.

you can refer to it within your code as self.button_1:

class Form1(Form1Template):
    # .. Somewhere inside Form1 ...
    self.button_1.text = "Click me"

However, this isn’t the only way to do it. Components are just Python classes, so you can construct new instances entirely in code:

class Form1(Form1Template):
    # .. Somewhere inside Form1 ...
    button_1 = Button()

This Button exists in Python, but it has not been added to the Form yet - we’ll show you how in the Containers section.

First we’ll cover more about what you can do with components - properties and events.

Properties

Components have properties that determine how they look and how they behave. Properties can be modified in the Anvil Editor using the Properties Panel (on the right below the Toolbox):

The Anvil Editor with the Properties Panel highlighted (it's in the bottom-right).

The Properties Panel allows you to edit a component’s content, appearance and behaviour.

You can adjust a component’s appearance by setting a property:

self.button_1.text = "Click me"

You can also read data from a component by reading properties (for example the text property of a TextBox component contains whatever text the user has entered in the box).

latest_user_input = self.text_box_1.text

The properties of all Anvil’s built-in components can be found in the API Reference.

If you’re creating components in code, you can pass in initial values for the properties when you create the component, for example Button(text="Click me").

Every component also has a property called tag, which is for you to store any extra data you like. By default, it’s an empty object that you can store attributes on:

self.my_textbox.tag.foo = "bar"

Events

Components can also raise events. For example, when a Button is clicked, it raises the click event.

You can see what events a component raises in the visual designer. This example is for a Button component:

The bottom of the Properties Panel, where you can see the events available for this component. There's an input box for each event, where you can enter the name of a method to bind to. The `click` event has `handle_click` written in its input box.

This Button calls self.handle_click when it is clicked.

To define what to do when an event is raised, you can enter a method name in the box. This is called ‘binding’ a method to an event. In the example above, the click event has the handle_click method bound to it.

The methods you bind must belong to the Form that the component is on. If the Button is in Form1 and it has handle_click bound to it, then your Form1 code must look like this:

class Form1(Form1Template):

  # ...

  def handle_click(self, **event_args):
    # Any code you write here will run when the button is clicked

There’s a shortcut to create event handlers: you can click on the blue arrows next to the event to get a click handler automatically defined for you in code:

Automatically creating an event handler.

Automatically creating an event handler.

For a full list of what events each component raises, see the API Reference.

The event_args argument

Every event handler has **event_args as a parameter. This contains useful data about the event. (The ** soaks up any extra keyword arguments that come with the event, and puts them all in a dict called event_args.)

event_args always contains:

  • event_name, for example ‘click’
  • sender, the Python object that triggered the event. For example, a click event triggered by a Link will have the Link object as the sender. You could use this to style the Link differently to show that it has been followed.

Other event_args may be present depending on the event, for example the precise mouse position. To discover what is available in **event_args for a particular event, look at the API Reference. Alternatively, run print(event_args) at the top of the event handler, run your app and take a look at the Output Panel.

Always use an **event_args if you’re defining your own event, in case any new arguments get added that you need to soak up.

Setting event handlers in code

As well as setting event handlers using the Editor as described above, you can set event handlers in code. This allows you to change the behaviour of your app while it is running.

You can set event handlers in code by calling set_event_handler(event_name, fn) on any component. event_name is the name of the event that’s displayed in the Properties Panel - for example, click. If you’re unsure of the event_name, look at the API Reference.

def handle_click(**event_args):
  alert("The button got clicked!")

self.button_1.set_event_handler('click', handle_click)

Raising events from code

You can raise an event on any component by calling the raise_event() method.

self.button_1.raise_event('click')

Any extra keyword parameters to raise_event() get passed to the event handler function. The sender argument will be the component on which raise_event() was called.

self.button_1.raise_event('click', speed="ludicrous")

You can raise an event on all children on a container using raise_event_on_children; see Containers for more detail.

Custom events

You’re not limited to the events in the Properties Panel. You can raise a custom event on any component using any event name beginning with x-.

# Set a custom event handler ...
self.button_1.set_event_handler('x-foo', self.handle_foo)
# ...define the `handle_foo` function
# This will be called when the 'x-foo' event is raised
def handle_foo(self, **event_args):
  print("The x-foo event was raised!")

# ...

# Raise the event somewhere else.
# This will call self.handle_foo
# with self.button_1 as the `sender` argument.
self.button_1.raise_event('x-foo')

Every event handler has **event_args as a parameter, so this must be included in the handle_foo function above.

Ensure the name of your custom event begins with x- to avoid conflicting with any built-in event names.

The show and hide events

Some actions can only be performed after a component is added to the web page in the browser. For example, a Canvas component cannot discover the size of its drawing area until it is added to the page – so a Form cannot usefully draw on a Canvas during its __init__ function. Instead, the drawing code must run when the Form is added to the page.

To help handle these situations, all components have a show and hide event, which trigger when the component is added to, or removed from, the page.

The show event does not necessarily mean the component is visible to the eye - a component may be invisible, but its show event still fires when it is added to the page. To be precise, these events trigger after the component is added to the browser’s HTML DOM.

show and hide propagate across containers: If a component’s container is added to the page, it too is added to the page. A container’s show or hide event is raised after all its children.

Containers

Some components can contain other components. We call these containers, and they all inherit from the Container class. (All Forms are also containers.)

For a full list of container components, see Components: Containers.

You can add a component to a container in Python by calling the container’s add_component() method.

You can call a container’s get_components() method to get a list of all the components that have been added to it.

Parents and children

You can look up a component’s container with the .parent attribute. If a component has not yet been added to a container, its .parent attribute is None.

print(btn.parent)
# prints "<anvil.XYPanel object>" for a button inside an XY Panel

Try to avoid using multiple .parent attributes chained together to go up the component hierarchy.

You will probably find your code is more robust if you use get_open_form() to get a reference to the currently-open Form and find the component you’re looking for from there.

Removing components

To remove a component from a container, call the component’s remove_from_parent() method.

btn.remove_from_parent()

To remove all components from a container, call the container’s clear() method.

self.xy_panel_1.clear()

Raising an event on all children

To raise an event on all components in a container, call the raise_event_on_children method

container.raise_event_on_children(event_name, extra_args)

This takes exactly the same parameters as component.raise_event, and is subject to the same constraints on event names.

It is especially useful when you want to signal to all children of a RepeatingPanel without already having explicit references to those children.

Container Properties

Container Properties are properties that control the relationship between a component and the container it is in; the argument names and their meanings depend on the type of container. They are visible in the Properties Panel in the Anvil Editor. They can also be passed as keyword arguments to add_component.

For example, XYPanels have x, y, and width container properties, which determine the position of the component. You can specify them in the designer:

Container properties are at the bottom of the
Properties Panel

Container properties are at the bottom of the
Properties Panel

Or you can pass them as keyword arguments when you call add_component() in your code:

btn = Button(text="Click me")
self.xy_panel_1.add_component(btn, x=100, y=100)

For more information on the container properties available for each container type, consult the Anvil API Reference.

Data Bindings

Read the full documentation on Data Bindings for more detail about Data Bindings and when you might find them useful.

Data Bindings are a tidy way to define a relationship between a component’s property and some underlying data - they associate a property of a component with a single Python expression. The relationship is defined in one place so you don’t need to re-write the code in many different parts of your app.

Data Bindings are be defined in the Properties Panel of the Anvil Editor. You select a property from the Dropdown and write a Python expression in the box.

Properties Panel for a TextBox
with two Data Bindings.

Properties Panel for a TextBox
with two Data Bindings.

self here refers to the Form that this component is on

The Python expression can use any attribute or method of the Form that the component is on. The Form is available as self - you can use anything that looks like self.<something>

The Data Binding is evaluated when any of these things happen:

  • when self.init_components(**properties) gets called in the __init__ method
  • when self.refresh_data_bindings() is called
  • when self.item is set

A component can have any number of Data Bindings (one for each of its properties).