ToggleButton Behavior

The ToggleButtonBehavior mixin class provides toggle button behavior for Kivy widgets. You can combine this class with other widgets to add specialized on/off state management with optional radio button grouping.

For an overview of behaviors, please refer to the behaviors documentation.

Quick Overview

TOGGLE BUTTON BEHAVIOR (extends ButtonBehavior)

STATE

TYPE

DESCRIPTION

pressed

read-only

Currently touched?

activated

read/write

Persistent on/off state

always_release

read/write

Always fire on_release?

allow_no_selection

read/write

Allow button off?

GROUPING

group

read/write

Group identifier (string or tuple)

CONFIGURATION

toggle_on

read/write

‘press’ or ‘release’

EVENTS

on_press(touch)

First touch down on button

on_release(touch)

All touches released

on_cancel(touch)

Touch moved outside bounds

METHODS

<togglebutton_instance>.get_group()

Get widgets in button’s group

ToggleButtonBehavior.get_group(name)

Get widgets by global group name

ToggleButtonBehavior.get_group( (owner, name))

Get widgets by scoped group

Examples

Basic toggle with visual feedback:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.uix.behaviors import ToggleButtonBehavior

class MyToggle(ToggleButtonBehavior, Label):
    Builder.load_string('''
<MyToggle>:
    canvas.before:
        Color:
            rgb: self.color
            a: 0.25
        Rectangle:
            size: self.size
            pos: self.pos
    ''')

    def on_activated(self, instance, value):
        self.color = [0, 1, 0, 1] if value else [1, 1, 1, 1]

class SampleApp(App):
    def build(self):
        return MyToggle()

SampleApp().run()

Radio button group behavior:

from kivy.lang import Builder
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.behaviors import ToggleButtonBehavior


class MyToggle(ToggleButtonBehavior, Label):
    Builder.load_string('''
<MyToggle>:
    canvas.before:
        Color:
            rgb: self.color
            a: 0.25
        Rectangle:
            size: self.size
            pos: self.pos
    ''')

    def on_activated(self, instance, value):
        self.color = [0, 1, 0, 1] if value else [1, 1, 1, 1]


class SampleApp(App):
    def build(self):
        layout = BoxLayout()
        for i in range(3):
            btn = MyToggle(
                text=f"Option {i + 1}",
                group="options",
                allow_no_selection=False,
            )
            layout.add_widget(btn)
        return layout


SampleApp().run()

Scoped groups for reusable components:

from kivy.lang import Builder
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.behaviors import ToggleButtonBehavior


class MyToggle(ToggleButtonBehavior, Label):
    Builder.load_string('''
<MyToggle>:
    canvas.before:
        Color:
            rgb: self.color
            a: 0.25
        Rectangle:
            size: self.size
            pos: self.pos
    ''')

    def on_activated(self, instance, value):
        self.color = [0, 1, 0, 1] if value else [1, 1, 1, 1]


class ToggleRow(BoxLayout):
    '''Reusable component with scoped group.'''

    def __init__(self, label_prefix="Option", **kwargs):
        super().__init__(**kwargs)
        for i in range(3):
            btn = MyToggle(
                text=f"{label_prefix}, Col {i + 1}",
                # group=("options"),  # Global, not scoped

                # Scoped to this row (ToggleRow instance)
                group=(self, "options"),

                allow_no_selection=False,
                activated=i == 0,
            )
            self.add_widget(btn)


class SampleApp(App):
    def build(self):
        layout = BoxLayout(orientation="vertical")
        # Each row has independent "options" group
        layout.add_widget(ToggleRow(label_prefix="Row 1"))
        layout.add_widget(ToggleRow(label_prefix="Row 2"))
        return layout


SampleApp().run()

See ToggleButtonBehavior for details.

class kivy.uix.behaviors.togglebutton.ToggleButtonBehavior(**kwargs)[source]

Bases: ButtonBehavior

Mixin to add toggle button behavior to any Kivy widget.

This mixin extends ButtonBehavior to provide persistent on/off state that survives beyond the press/release interaction. It supports grouping multiple toggles together for radio button behavior.

State Management

Unlike the transient pressed property from ButtonBehavior (which is True only during active touch), the activated property maintains persistent state:

  • activated=True: Button is in “on” state (persists after release)

  • activated=False: Button is in “off” state (default)

The activated property can be set programmatically or toggled by user interaction. When allow_no_selection is False, attempts to deactivate the last active button in a group are rejected: programmatic attempts log a warning, while touch interactions are silently blocked.

Group Behavior

When buttons share a group, they act like radio buttons:

  • Activating one button automatically deactivates others in the group

  • Only one button per group can be active at a time

  • allow_no_selection controls whether all buttons can be deactivated

Without group: Buttons toggle independently With group: Buttons behave as mutually exclusive options

Group Scoping

Groups can be either global or scoped to a specific widget owner:

Global groups (string):

ToggleButton:
    group: "mygroup"  # Shared across entire application

Scoped groups (tuple):

ToggleButton:
    group: (root, "mygroup")  # Scoped to 'root' widget

Scoped groups allow multiple widget hierarchies to use the same group name without interference. This is useful when creating reusable components with internal toggle groups.

Example:

<MyComponent>:
    # These groups won't conflict with other MyComponent instances
    ToggleButton:
        group: (root, "options")
    ToggleButton:
        group: (root, "options")

Events

Inherits all events from ButtonBehavior:
  • on_press(): First touch down

  • on_release(): All touches released

  • on_cancel(): Touch moved outside bounds

Added in version 1.8.0.

Changed in version 3.0.0: - Replaced state OptionProperty with activated AliasProperty - Improved group management with automatic cleanup - Added scoped group support via tuple syntax - Replaced get_widgets(groupname) static method with unified get_group() descriptor that works as both instance and class method

activated

Persistent toggle state of the button.

  • True: Button is in “on” state

  • False: Button is in “off” state

Unlike pressed (which is True only during touch), activated maintains state after release. Can be set programmatically or toggled by user interaction.

When button is in a group, setting activated=True automatically deactivates other buttons in that group.

When allow_no_selection is False, attempts to set activated=False on the last active button in a group log a warning and are rejected. Touch interactions are silently blocked without warnings.

activated is an AliasProperty and defaults to False.

Added in version 3.0.0.

allow_no_selection

Specifies whether widgets in a group allow no selection (all deselected).

  • True (default): Clicking active button deactivates it (all buttons off)

  • False: At least one button must remain active (radio button behavior)

When False, attempts to deactivate the last active button are rejected: programmatic activated = False logs a warning, while touch interactions are silently blocked.

Only applies when group is set.

Added in version 1.9.0.

allow_no_selection is a BooleanProperty and defaults to True.

get_group()

Get widgets in a group.

This descriptor works as both an instance method and a class method, providing a unified API for accessing group widgets.

As instance method (no arguments):

Returns all widgets in the same group as this instance, including this instance itself.

Example:

# Get all widgets in my_button's group
widgets = my_button.get_group()
for w in widgets:
    print(w.text)
del widgets  # Release immediately
As class method (pass group identifier):

Returns all widgets in the specified group. Useful when you don’t have a widget instance but know the group identifier.

Example:

# Get widgets by global group name
widgets = ToggleButtonBehavior.get_group("options")

# Get widgets by scoped group
widgets = ToggleButtonBehavior.get_group((panel, "filters"))

# Useful after removing a widget
my_group = widget.group
widget.parent.remove_widget(widget)
remaining = ToggleButtonBehavior.get_group(my_group)

Warning

Always release the result immediately! Holding references prevents garbage collection:

widgets = button.get_group()
# use widgets
del widgets

Note

List may contain recently deleted widgets that haven’t been garbage collected yet.

Returns:

List of widget instances in the group (empty list if group doesn’t exist or has no members)

Added in version 3.0.0: Replaces the old get_widgets(groupname) static method with a unified descriptor that works as both instance and class method.

group

Group of the button. If None, no group will be used (button toggles independently).

Accepts two formats:

  • Hashable value (string, int, etc.): Global group shared across entire application

  • Tuple (owner, name): Scoped group limited to owner’s context

Global groups (any hashable):

group: "mygroup"
group: 42
group: MyEnum.OPTION_A

Scoped groups (tuple of any object + hashable name):

group: (root, "mygroup")
group: (self.parent, "options")
group: (app.current_screen, "filters")
Tuple format: (owner, name)
  • owner: Any object to scope the group to (typically a widget). Uses object identity, not equality. Can be weakly referenced.

  • name: Hashable identifier for the group (string, int, enum, etc.)

Only one button per group can be active at a time. When a button in a group is activated, all other buttons in that group are automatically deactivated.

Scoped groups allow multiple widget instances to use the same group name without interference, making it easier to create reusable components.

Example of reusable component:

# Multiple instances won't interfere with each other
<FilterPanel>:
    ToggleButton:
        group: (root, "size")
        text: "Small"
    ToggleButton:
        group: (root, "size")
        text: "Large"

# Each FilterPanel instance has independent "size" groups
FilterPanel:
    id: panel1
FilterPanel:
    id: panel2

group is a ObjectProperty and defaults to None.

Changed in version 3.0.0: Added support for tuple format to enable scoped groups.

on_activated(instance, value)[source]

Event handler called when activated state changes.

Override this method to respond to state changes.

Parameters:
  • instance – This button instance

  • value – New activated state (True/False)

toggle_on

Specifies which ButtonBehavior event triggers the toggle state change.

  • “release” (default) — The state toggles when the button is released.

  • “press” — The state toggles immediately when the button is pressed.

This property allows adjusting when the toggle action occurs, depending on the desired interaction style. It can be changed dynamically at runtime, and the new behavior takes effect immediately.

toggle_on is an OptionProperty and accepts either "press" or "release". Defaults to "release".