Version

Quick search

Table Of Contents

Behaviors

New in version 1.8.0.

Behavior mixin classes

This module implements behaviors that can be mixed in with existing base widgets. The idea behind these classes is to encapsulate properties and events associated with certain types of widgets.

Isolating these properties and events in a mixin class allows you to define your own implementation for standard kivy widgets that can act as drop-in replacements. This means you can re-style and re-define widgets as desired without breaking compatibility: as long as they implement the behaviors correctly, they can simply replace the standard widgets.

Adding behaviors

Say you want to add Button capabilities to an Image, you could do:

class IconButton(ButtonBehavior, Image):
    pass

This would give you an Image with the events and properties inherited from ButtonBehavior. For example, the on_press and on_release events would be fired when appropriate:

class IconButton(ButtonBehavior, Image):
    def on_press(self):
        print("on_press")

Or in kv:

IconButton:
    on_press: print('on_press')

Naturally, you could also bind to any property changes the behavior class offers:

def state_changed(*args):
    print('state changed')

button = IconButton()
button.bind(state=state_changed)

Note

The behavior class must always be _before_ the widget class. If you don’t specify the inheritance in this order, the behavior will not work because the behavior methods are overwritten by the class method listed first.

Similarly, if you combine a behavior class with a class which requires the use of the methods also defined by the behavior class, the resulting class may not function properly. For example, when combining the ButtonBehavior with a Slider, both of which use the on_touch_up() method, the resulting class may not work properly.

Changed in version 1.9.1: The individual behavior classes, previously in one big behaviors.py file, has been split into a single file for each class under the behaviors module. All the behaviors are still imported in the behaviors module so they are accessible as before (e.g. both from kivy.uix.behaviors import ButtonBehavior and from kivy.uix.behaviors.button import ButtonBehavior work).

class kivy.uix.behaviors.ButtonBehavior(**kwargs)

Bases: builtins.object

Mixin to add button behavior to any Kivy widget.

This mixin enables widgets to respond to press/release interactions with automatic multi-touch support. It provides three specialized events: on_press(), on_release(), and on_cancel(), along with a reactive pressed property.

Button State Management

Tracks active touches internally using a set-based approach. Each touch gets a unique ID (supports multi-touch). When first touch enters widget bounds, button becomes pressed. When ALL touches are released or cancelled, button returns to unpressed state. The pressed property is True when any touches are active.

Multi-Touch Behavior

The button automatically handles multiple simultaneous touches:

  • First touch down: Triggers on_press(), sets pressed to True

  • Additional touches: Tracked but don’t trigger on_press() again

  • Touch release: Only triggers on_release() after ALL touches released

  • Touch cancel: Removes touch from tracking, updates pressed state

Release Modes

Controlled by always_release property:

  • False (default): Standard button behavior. on_release() only fires if touch ends within button bounds. on_cancel() fires when touch moves outside bounds during drag (touch move).

  • True: Always fires on_release() regardless of touch position. on_cancel() never fires. Useful for drag-and-drop or gesture-based interfaces.

Events

on_press()

First touch down on button

on_release()

All touches released (respects always_release mode)

on_cancel()
Touch moved outside bounds during drag (only when always_release

is False)

Changed in version 3.0.0: - Replaced state OptionProperty with pressed BooleanProperty - Made pressed read-only via AliasProperty - Added on_cancel() event - Improved multi-touch handling with explicit touch sets

on_cancel()

Event handler called when touch leaves button bounds during drag.

This event is only fired when always_release is False and a touch moves outside the button’s bounds during a drag operation. It provides an opportunity to give visual feedback that the button action has been cancelled.

Use this to restore the button’s original appearance or cancel any pending actions that would have occurred on release.

New in version 3.0.0.

on_press()

Event handler called when the button is pressed.

This event is fired when the first touch down occurs on the button. In multi-touch scenarios, only the first touch triggers this event.

on_release()

Event handler called when the button is released.

This event is fired when the last active touch is released, and only if: - The touch is released within button bounds, OR - The always_release property is True

on_touch_down(touch)

Handle touch down events.

Implements core press detection:

  1. Test collision with widget bounds

  2. Grab touch if colliding (marks widget as touch owner)

  3. Add to active touches tracking

  4. Dispatch on_press() on first touch

Parameters:

touchMotionEvent instance

Returns:

True if event was handled (collided with widget)

on_touch_move(touch)

Handle touch move events.

Detects when touch moves outside button bounds during drag and triggers cancellation if always_release is False.

Cancellation flow: 1. Touch owned by this widget moves outside bounds 2. Remove from active touches, add to cancelled touches 3. Dispatch on_cancel() if this was the last active touch

Parameters:

touchMotionEvent instance

Returns:

True if event was handled

on_touch_up(touch) bool

Handle touch up events.

Implements release detection:

  1. Verify we own this touch

  2. Ungrab touch to release ownership

  3. Remove from active/cancelled tracking

  4. Dispatch on_release() if appropriate: - Touch wasn’t cancelled, AND - (Touch ended within bounds OR always_release is True), AND - This was the last active touch

Parameters:

touchMotionEvent instance

Returns:

True if event was handled

class kivy.uix.behaviors.CodeNavigationBehavior[source]

Bases: kivy.event.EventDispatcher

Code navigation behavior. Modifies the navigation behavior in TextInput to work like an IDE instead of a word processor. Please see the code navigation behaviors module documentation for more information.

New in version 1.9.1.

class kivy.uix.behaviors.CompoundSelectionBehavior(**kwargs)

Bases: builtins.object

The Selection behavior mixin implements the logic behind keyboard and touch selection of selectable widgets managed by the derived widget. Please see the compound selection behaviors module documentation for more information.

New in version 1.9.0.

clear_selection()

Deselects all the currently selected nodes.

deselect_node(node)

Deselects a possibly selected node.

It is called by the controller when it deselects a node and can also be called from the outside to deselect a node directly. The derived widget should overwrite this method and change the node to its unselected state when this is called

Parameters:
node

The node to be deselected.

Warning

This method must be called by the derived widget using super if it is overwritten.

get_index_of_node(node, selectable_nodes)

(internal) Returns the index of the node within the selectable_nodes returned by get_selectable_nodes().

get_selectable_nodes()

(internal) Returns a list of the nodes that can be selected. It can be overwritten by the derived widget to return the correct list.

This list is used to determine which nodes to select with group selection. E.g. the last element in the list will be selected when home is pressed, pagedown will move (or add to, if shift is held) the selection from the current position by negative page_count nodes starting from the position of the currently selected node in this list and so on. Still, nodes can be selected even if they are not in this list.

Note

It is safe to dynamically change this list including removing, adding, or re-arranging its elements. Nodes can be selected even if they are not on this list. And selected nodes removed from the list will remain selected until deselect_node() is called.

Warning

Layouts display their children in the reverse order. That is, the contents of children is displayed form right to left, bottom to top. Therefore, internally, the indices of the elements returned by this function are reversed to make it work by default for most layouts so that the final result is consistent e.g. home, although it will select the last element in this list visually, will select the first element when counting from top to bottom and left to right. If this behavior is not desired, a reversed list should be returned instead.

Defaults to returning children.

goto_node(key, last_node, last_node_idx)

(internal) Used by the controller to get the node at the position indicated by key. The key can be keyboard inputs, e.g. pageup, or scroll inputs from the mouse scroll wheel, e.g. scrollup. ‘last_node’ is the last node selected and is used to find the resulting node. For example, if the key is up, the returned node is one node up from the last node.

It can be overwritten by the derived widget.

Parameters:
key

str, the string used to find the desired node. It can be any of the keyboard keys, as well as the mouse scrollup, scrolldown, scrollright, and scrollleft strings. If letters are typed in quick succession, the letters will be combined before it’s passed in as key and can be used to find nodes that have an associated string that starts with those letters.

last_node

The last node that was selected.

last_node_idx

The cached index of the last node selected in the get_selectable_nodes() list. If the list hasn’t changed it saves having to look up the index of last_node in that list.

Returns:

tuple, the node targeted by key and its index in the get_selectable_nodes() list. Returning (last_node, last_node_idx) indicates a node wasn’t found.

select_node(node)

Selects a node.

It is called by the controller when it selects a node and can be called from the outside to select a node directly. The derived widget should overwrite this method and change the node state to selected when called.

Parameters:
node

The node to be selected.

Returns:

bool, True if the node was selected, False otherwise.

Warning

This method must be called by the derived widget using super if it is overwritten.

select_with_key_down(keyboard, scancode, codepoint, modifiers, **kwargs)

Processes a key press. This is called when a key press is to be used for selection. Depending on the keyboard keys pressed and the configuration, it could select or deselect nodes or node ranges from the selectable nodes list, get_selectable_nodes().

The parameters are such that it could be bound directly to the on_key_down event of a keyboard. Therefore, it is safe to be called repeatedly when the key is held down as is done by the keyboard.

Returns:

bool, True if the keypress was used, False otherwise.

select_with_key_up(keyboard, scancode, **kwargs)

(internal) Processes a key release. This must be called by the derived widget when a key that select_with_key_down() returned True is released.

The parameters are such that it could be bound directly to the on_key_up event of a keyboard.

Returns:

bool, True if the key release was used, False otherwise.

select_with_touch(node, touch=None)

(internal) Processes a touch on the node. This should be called by the derived widget when a node is touched and is to be used for selection. Depending on the keyboard keys pressed and the configuration, it could select or deslect this and other nodes in the selectable nodes list, get_selectable_nodes().

Parameters:
node

The node that received the touch. Can be None for a scroll type touch.

touch

Optionally, the touch. Defaults to None.

Returns:

bool, True if the touch was used, False otherwise.

class kivy.uix.behaviors.CoverBehavior(**kwargs)

Bases: builtins.object

The CoverBehavior mixin provides rendering a texture covering full widget size keeping aspect ratio of the original texture.

New in version 1.10.0.

class kivy.uix.behaviors.DragBehavior(**kwargs)

Bases: builtins.object

The DragBehavior mixin provides Drag behavior. When combined with a widget, dragging in the rectangle defined by drag_rectangle will drag the widget. Please see the drag behaviors module documentation for more information.

New in version 1.8.0.

class kivy.uix.behaviors.EmacsBehavior(**kwargs)

Bases: builtins.object

A mixin that enables Emacs-style keyboard shortcuts for the TextInput widget. Please see the Emacs behaviors module documentation for more information.

New in version 1.9.1.

delete_word_left()

Delete text left of the cursor to the beginning of word

delete_word_right()

Delete text right of the cursor to the end of the word

class kivy.uix.behaviors.FocusBehavior(**kwargs)

Bases: builtins.object

Provides keyboard focus behavior. When combined with other FocusBehavior widgets it allows one to cycle focus among them by pressing tab. Please see the focus behavior module documentation for more information.

New in version 1.9.0.

get_focus_next()

Returns the next focusable widget using either focus_next or the children similar to the order when tabbing forwards with the tab key.

get_focus_previous()

Returns the previous focusable widget using either focus_previous or the children similar to the order when the tab + shift keys are triggered together.

hide_keyboard()

Convenience function to hide the keyboard in managed mode.

keyboard_on_key_down(window, keycode, text, modifiers)

The method bound to the keyboard when the instance has focus.

When the instance becomes focused, this method is bound to the keyboard and will be called for every input press. The parameters are the same as kivy.core.window.WindowBase.on_key_down().

When overwriting the method in the derived widget, super should be called to enable tab cycling. If the derived widget wishes to use tab for its own purposes, it can call super after it has processed the character (if it does not wish to consume the tab).

Similar to other keyboard functions, it should return True if the key was consumed.

keyboard_on_key_up(window, keycode)

The method bound to the keyboard when the instance has focus.

When the instance becomes focused, this method is bound to the keyboard and will be called for every input release. The parameters are the same as kivy.core.window.WindowBase.on_key_up().

When overwriting the method in the derived widget, super should be called to enable de-focusing on escape. If the derived widget wishes to use escape for its own purposes, it can call super after it has processed the character (if it does not wish to consume the escape).

See keyboard_on_key_down()

show_keyboard()

Convenience function to show the keyboard in managed mode.

class kivy.uix.behaviors.HoverBehavior(**kwargs)

Bases: builtins.object

Mixin to add hover detection and event handling to any Kivy widget.

This mixin enables widgets to respond to mouse hover events with three specialized events: on_hover_enter(), on_hover_update(), and on_hover_leave(). It also provides a reactive hovered property.

Hover State Management

Tracks active hover events internally. Each hover event gets a unique ID (supports multi-touch hover). When a hover enters widget bounds, it’s tracked. When it leaves, it’s removed. The hovered property is True when any hover events are active.

Event Propagation Modes

  • “default”: Standard behavior. Events go to children first. If no child accepts, the event is offered to this widget.

  • “all”: Forces dispatch to both children AND this widget, regardless of whether children accept. Use when parent needs to track hovers even while children handle them (e.g., container with hover effects).

  • “self”: Skips children entirely. This widget captures all hover events within its bounds. Use for widgets that should be “opaque” to hover (e.g., popup overlays).

Static Hover Re-dispatching

By default, hover events are re-dispatched once when the mouse is stationary AND the time since the last dispatch exceeds 1/30s. This enables proper hover state tracking when content moves under a stationary cursor (e.g., scrolling with mousewheel).

All three hover events (enter/update/leave) are affected:

Configure globally before creating widgets:

# Disable re-dispatching entirely
HoverBehavior.set_hover_update_interval(-1)

# Re-dispatch once after 0.1s (max 10 updates per second)
HoverBehavior.set_hover_update_interval(0.1)

# Default: re-dispatch once after 1/30s (max 30 updates per second)
HoverBehavior.set_hover_update_interval(1/30)

Combining with Motion Filters

For most use cases, combine HoverBehavior with motion event filters from motion:

Example - ScrollView with Collision Filter:

from kivy.uix.behaviors.motion import MotionCollideBehavior

class HoverScrollView(MotionCollideBehavior, ScrollView):
    # Filters hover outside stencil bounds
    pass

class HoverItem(HoverBehavior, MotionCollideBehavior, Label):
    # Only receives hover when visible
    pass

Example - Blocking Hover Leak-Through:

from kivy.uix.behaviors.motion import MotionBlockBehavior

class OpaqueButton(MotionBlockBehavior, Button):
    # Blocks all unregistered motion events
    pass

layout = FloatLayout()
layout.add_widget(HoverScrollView())  # Background
layout.add_widget(OpaqueButton())     # Foreground
# Hovering button won't trigger ScrollView hover

Events

on_hover_enter()

First collision with widget bounds

on_hover_update()

Hover moved within bounds

on_hover_leave()

Hover left widget bounds

Internal State

For subclassing: _hover_ids (dict) maps active hover UIDs to positions {uid: (x, y)}. Updated by hover events. Empty when not hovered.

classmethod get_hover_update_interval()

Get the current hover re-dispatch interval.

Returns:

Current interval in seconds, or negative if disabled

Example:

interval = HoverBehavior.get_hover_update_interval()
if interval < 0:
    print("Hover re-dispatching disabled")
else:
    print(f"Re-dispatches every {interval:.3f} seconds")
on_hover_enter(motion_event)

Called when hover first enters widget bounds.

Override this method to respond to hover enter events.

Parameters:

motion_eventMotionEvent

on_hover_leave(motion_event)

Called when hover exits widget bounds.

Override this method to respond to hover leave events.

Parameters:

motion_eventMotionEvent

on_hover_update(motion_event)

Called when hover moves within widget bounds.

If the mouse doesn’t move AND enough time has passed since the last dispatch, this is called once.

Disable re-dispatching via set_hover_update_interval(-1) if this behavior is not needed.

Parameters:

motion_eventMotionEvent

on_motion(event_type: str, motion_event) bool

Handle incoming motion events, filtering for hover events.

Main entry point for motion events. Filters for hover events and handles them according to hover_mode. Non-hover events pass to parent.

Parameters:
  • event_type – Type of motion event (“begin”, “update”, “end”)

  • motion_eventMotionEvent instance

Returns:

True if event was handled

classmethod set_hover_update_interval(interval)

Configure hover re-dispatching interval globally.

Controls the minimum time between hover re-dispatches when the mouse is stationary. Re-dispatches once when:

  1. Mouse hasn’t moved, AND

  2. Time since last dispatch exceeds interval

This affects all three hover events (enter/update/leave) and is essential for scenarios where content moves under a static cursor (e.g., scrolling with mousewheel).

When enabled, the system re-checks which widgets should receive hover events, allowing proper enter/leave events as widgets scroll in/out of view.

This configuration applies to all HoverBehavior widgets and can be called before any widgets are instantiated.

Parameters:

interval – Seconds between re-dispatches. Use negative value to disable re-dispatching entirely

Example:

# Disable re-dispatching (no scroll hover updates)
HoverBehavior.set_hover_update_interval(-1)

# Re-dispatch once after 0.1s (max 10 updates per second)
HoverBehavior.set_hover_update_interval(0.1)

# Default: re-dispatch once after 1/30s (max 30 updates per second)
HoverBehavior.set_hover_update_interval(1/30)

Note

When disabled (negative interval), hover events only fire when the mouse actually moves. Content scrolling under a static cursor will not trigger enter/update/leave events.

class kivy.uix.behaviors.MotionBlockBehavior[source]

Bases: builtins.object

Mixin to block unregistered motion events from passing through.

Makes widgets “opaque” to motion events they haven’t registered to handle. When a motion event collides with the widget but the widget hasn’t registered for that event type, the event is blocked from propagating to widgets behind it.

Generic Design

Works with ANY motion event type (hover, drag, custom events). Prevents motion events from “leaking through” foreground widgets to background widgets.

Comparison with HoverBehavior

  • MotionBlockBehavior: Blocks ALL unregistered motion event types

  • HoverBehavior (hover_mode=’self’): Only blocks hover events with more fine-grained control

For hover-specific blocking with more control, consider using HoverBehavior with hover_mode=’self’ instead.

Technical Note

The collision check uses widget.collide_point(*motion_event.pos)(). For custom collision shapes, override collide_point() in your widget.

Grabbed Events

Grabbed events always pass through, even if not registered. This ensures proper event lifecycle - if a widget grabs an event, it must receive all subsequent updates and the end event.

on_motion(event_type: str, motion_event) bool[source]

Block unregistered motion events that collide with widget.

Processing logic:

  1. If grabbed by this widget -> pass to super() (process)

  2. If collides but NOT registered -> return True (block)

  3. Otherwise -> pass to super() (continue propagation)

Parameters:
  • event_type – Motion event type (“begin”, “update”, “end”)

  • motion_event – MotionEvent to potentially block

Returns:

True if event was blocked or handled, False otherwise

class kivy.uix.behaviors.MotionCollideBehavior[source]

Bases: builtins.object

Mixin to filter motion events based on collision detection.

This mixin overrides on_motion() to only process events that either:

  1. Collide with the widget’s bounds, OR

  2. Are grabbed events (motion_event.grab_current is self)

Generic Design

Works with ANY motion event type (hover, drag, custom events). Commonly used with HoverBehavior but not limited to hover events.

Primary Use Case - StencilView

Essential for widgets that use stencil clipping (RecycleView, ScrollView). Without this mixin, widgets outside the stencil bounds can still receive motion events, leading to confusing behavior where invisible items respond.

Technical Note

The collision check uses widget.collide_point(*motion_event.pos)(), which tests against the widget’s bounding box. For complex shapes, override collide_point() in your widget class for custom collision logic.

Grabbed Events

Grabbed events always pass through, even if they don’t collide. This ensures proper event completion - if a widget grabbed an event (e.g., on hover enter), it must receive the end event even if the cursor moved outside bounds.

on_motion(event_type: str, motion_event) bool[source]

Filter motion events by collision or grab status.

Only processes events that:

  • Are currently grabbed by this widget, OR

  • Have position data and collide with widget bounds

Parameters:
  • event_type – Motion event type (“begin”, “update”, “end”)

  • motion_event – MotionEvent to potentially filter

Returns:

Result of super().on_motion() if passed filter, False otherwise

class kivy.uix.behaviors.ToggleButtonBehavior(**kwargs)

Bases: kivy.uix.behaviors.button.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 active property maintains persistent state:

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

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

The active 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 will be silently rejected.

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

Additional property events:

New in version 1.8.0.

Changed in version 3.0.0: - Replaced state OptionProperty with active AliasProperty - Added backward-compatible state alias - 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

on_active(instance, value)

Event handler called when active state changes.

Override this method to respond to state changes.

Parameters:
  • instance – This button instance

  • value – New active state (True/False)

class kivy.uix.behaviors.TouchRippleBehavior(**kwargs)

Bases: builtins.object

Touch ripple behavior.

Supposed to be used as mixin on widget classes.

Ripple behavior does not trigger automatically, concrete implementation needs to call ripple_show() respective ripple_fade() manually.

Example

Here we create a Label which renders the touch ripple animation on interaction:

class RippleLabel(TouchRippleBehavior, Label):

    def __init__(self, **kwargs):
        super(RippleLabel, self).__init__(**kwargs)

    def on_touch_down(self, touch):
        collide_point = self.collide_point(touch.x, touch.y)
        if collide_point:
            touch.grab(self)
            self.ripple_show(touch)
            return True
        return False

    def on_touch_up(self, touch):
        if touch.grab_current is self:
            touch.ungrab(self)
            self.ripple_fade()
            return True
        return False
ripple_fade()

Finish ripple animation on current widget.

ripple_show(touch)

Begin ripple animation on current widget.

Expects touch event as argument.

class kivy.uix.behaviors.TouchRippleButtonBehavior(**kwargs)

Bases: kivy.uix.behaviors.touchripple.TouchRippleBehavior

This mixin class provides a similar behavior to ButtonBehavior but provides touch ripple animation instead of button pressed/released as visual effect.

Events:
on_press

Fired when the button is pressed.

on_release

Fired when the button is released (i.e. the touch/click that pressed the button goes away).