Skip to content

Text Field

Text fields let users enter and edit text. They support validation, error states, leading icons, trailing icon buttons, heading labels, and supporting text.

Variants

Class Style
MorphTextField Default filled style
MorphTextFieldFilled Explicit filled variant
MorphTextFieldOutlined Outlined border style
MorphTextFieldRounded Fully rounded border style

Usage

from morphui.uix.textfield import MorphTextField, MorphTextFieldOutlined

# Basic
field = MorphTextField(hint_text="Enter name")

# Required field
field = MorphTextField(hint_text="Email", required=True, validator='email')

# Outlined with max length
field = MorphTextFieldOutlined(
    hint_text="Username",
    max_text_length=32,
)

Validation

Built-in validators are configured via the validator property:

field = MorphTextField(validator='email')
field = MorphTextField(validator='numeric')
field = MorphTextField(validator='integer')

For custom validation, subclass MorphTextValidator.

Error State

# Set error manually
field.error = True
field.error_message = "This field is required"

morphui.uix.textfield

Text field widgets for MorphUI.

This module provides single-line text input components with built-in validation, error state display, leading icon support, trailing icon button support, heading labels, and supporting text. Three visual styles are available: filled, outlined, and rounded.

CLASS DESCRIPTION
MorphTextValidator

Standalone validator that tracks error state and type.

MorphTextInput

Internal TextInput subclass with MorphUI theming.

MorphTextField

Filled text field (default style).

MorphTextFieldFilled

Explicit alias for the filled style.

MorphTextFieldOutlined

Outlined border style.

MorphTextFieldRounded

Fully rounded border style.

NO_ERROR = 'none' module-attribute

Constant representing no error state.

MorphTextValidator

Bases: EventDispatcher

error = BooleanProperty(False) class-attribute instance-attribute

Indicates whether the text widget is in an error state.

This property reflects the error state of the internal text. When True, the text widget is marked as having an error, When False, it is not in an error state.

:attr:error is a :class:~kivy.properties.BooleanProperty and defaults to False.

error_type = StringProperty('') class-attribute instance-attribute

The type of error associated with the current error state.

This property holds a string that describes the type of error encountered in the text input. It can be used to provide specific feedback to the user about the nature of the error. The possible values are the same as those defined for the :attr:validator property plus required and max_text_length.

:attr:error_type is a :class:~kivy.properties.StringProperty and defaults to an empty string.

required = BooleanProperty(False) class-attribute instance-attribute

Indicates whether the text is required.

When True, the :attr:text must contain valid text to be considered valid. When False, the text widget can be left empty without error.

:attr:required is a :class:~kivy.properties.BooleanProperty and defaults to False.

max_text_length = NumericProperty(0) class-attribute instance-attribute

The maximum length of the text input.

This property sets a limit on the number of characters that can be entered into the text widget. If the text exceeds this length, it will be truncated or rejected based on the implementation.

:attr:max_length is a :class:~kivy.properties.NumericProperty and defaults to 0, which means no limit.

validator = OptionProperty(None, allownone=True, options=['email', 'phone', 'date', 'time', 'datetime', 'daterange', 'numeric', 'alphanumeric']) class-attribute instance-attribute

The type of validation to apply to the text.

This property determines the kind of validation that will be performed on the text content. Supported options are: - 'email': Validates that the text is a properly formatted email address. - 'phone': Validates that the text is a properly formatted phone number. - 'date': Validates that the text is a properly formatted date. - 'time': Validates that the text is a properly formatted time. - 'datetime': Validates that the text is a properly formatted datetime. - 'daterange': Validates that the text is a valid date range. Where the separator is a hyphen (-) and the format is any of the supported date formats for each date, e.g., 'YYYY-MM-DD - YYYY-MM-DD'. For more information, see :meth:is_valid_daterange. - 'numeric': Validates that the text is a valid numeric value. - 'alphanumeric': Validates that the text contains only letters and numbers. When set to None, no validation is performed. :attr:validator is a :class:~kivy.properties.OptionProperty and defaults to None.

is_valid_email(text)

Check if the given text is a valid email address.

PARAMETER DESCRIPTION
text

The text input to validate.

TYPE: str

RETURNS DESCRIPTION
bool

True if the input is a valid email address, False otherwise.

is_valid_phone(text)

Check if the given text is a valid phone number.

PARAMETER DESCRIPTION
text

The text input to validate.

TYPE: str

RETURNS DESCRIPTION
bool

True if the input is a valid phone number, False otherwise.

is_valid_date(text)

Check if the given text is a valid date.

This method checks the text against various date formats to determine its validity. The supported formats are: - European format: 'DD/MM/YYYY' or 'DD-MM-YYYY' - ISO format: 'YYYY-MM-DD' - US format: 'MM/DD/YYYY' or 'MM-DD-YYYY'

PARAMETER DESCRIPTION
text

The text input to validate.

TYPE: str

RETURNS DESCRIPTION
bool

True if the input is a valid date, False otherwise.

is_valid_time(text)

Check if the given text is a valid time.

PARAMETER DESCRIPTION
text

The text input to validate.

TYPE: str

RETURNS DESCRIPTION
bool

True if the input is a valid time, False otherwise.

is_valid_datetime(text)

Check if the given text is a valid datetime.

Splits the text into date and time components and validates each part separately. Permits both 'T' and space as separators. Where the date must be the first part and the time the second part. Then checks if both parts are valid. The expected format is 'YYYY-MM-DDTHH:MM:SS' or 'YYYY-MM-DD HH:MM:SS'.

PARAMETER DESCRIPTION
text

The text input to validate.

TYPE: str

RETURNS DESCRIPTION
bool

True if the input is a valid datetime, False otherwise.

is_valid_daterange(text)

Check if the given text is a valid date range.

Splits the text into two date components using a hyphen (-) as the separator. Then checks if both parts are valid dates. The format is expected to be 'YYYY-MM-DD - YYYY-MM-DD'. But other date formats are also supported for each date. For more information, see :meth:is_valid_date.

PARAMETER DESCRIPTION
text

The text input to validate.

TYPE: str

RETURNS DESCRIPTION
bool

True if the input is a valid date range, False otherwise.

is_valid_numeric(text)

Check if the given text is a valid numeric value.

PARAMETER DESCRIPTION
text

The text input to validate.

TYPE: str

RETURNS DESCRIPTION
bool

True if the input is a valid numeric value, False otherwise.

is_valid_alphanumeric(text)

Check if the given text is a valid alphanumeric value.

PARAMETER DESCRIPTION
text

The text input to validate.

TYPE: str

RETURNS DESCRIPTION
bool

True if the input is a valid alphanumeric value, False otherwise.

validate(text)

Validate the given text based on the current settings.

This method checks the text against the required and validator properties to determine if it is valid.

PARAMETER DESCRIPTION
text

The text input to validate.

TYPE: str

RETURNS DESCRIPTION
bool

True if the text is valid according to the current settings, False otherwise.

MorphTextInput(**kwargs)

Bases: MorphIdentificationBehavior, MorphThemeBehavior, MorphContentLayerBehavior, MorphSurfaceLayerBehavior, MorphAutoSizingBehavior, MorphSizeBoundsBehavior, TextInput

minimum_width = NumericProperty(dp(80)) class-attribute instance-attribute

The minimum width of the TextInput based on content.

:attr:minimum_width is a :class:~kivy.properties.NumericProperty and defaults to dp(80).

row_height = AliasProperty(lambda self: self.line_height + self.line_spacing, bind=['line_height', 'line_spacing'], cache=True) class-attribute instance-attribute

The height of a single row of text.

:attr:row_height is a :class:~kivy.properties.AliasProperty.

minimum_height = AliasProperty(_get_minimum_height, cache=True, bind=['_lines', 'line_height', 'line_spacing', 'padding', 'multiline', 'password', 'maximum_height']) class-attribute instance-attribute

The minimum height of the TextInput based on content (read-only).

This property calculates the minimum height required to display all lines of text without clipping, taking into account line height, line spacing, and padding. If the TextInput is not multiline, it simply returns the line height.

:attr:minimum_height is a :class:~kivy.properties.AliasProperty.

maximum_height = NumericProperty(dp(300)) class-attribute instance-attribute

The maximum height of the TextInput when auto_height is enabled.

Sets the upper limit for the height of the TextInput when auto_height is True. This prevents the TextInput from growing excessively tall.

:attr:maximum_height is a :class:~kivy.properties.NumericProperty and defaults to dp(300).

cursor_path = AliasProperty(lambda self: [*(self.cursor_pos), self.cursor_pos[0], self.cursor_pos[1] - self.line_height], cache=True, bind=['cursor_pos', 'line_height']) class-attribute instance-attribute

The path points for the cursor line (read-only).

This property defines the points for drawing the cursor line based on the current cursor position and line height.

:attr:cursor_path is a :class:~kivy.properties.AliasProperty.

update_cursor(*args)

Update the cursor appearance based on focus and blink state.

This method updates the cursor's color and position based on whether the TextInput is focused and if the cursor blink is active.

It overrides the default behavior to ensure the cursor is displayed correctly with MorphUI theming.

MorphTextField(**kwargs)

Bases: MorphTextValidator, MorphHoverBehavior, MorphDelegatedThemeBehavior, MorphLeadingWidgetBehavior, MorphTripleLabelBehavior, MorphTrailingWidgetBehavior, MorphTypographyBehavior, MorphContentLayerBehavior, MorphInteractionLayerBehavior, MorphFloatLayout

A versatile text field widget with validation, theming, and flexible layout. Designed for various text input scenarios, it supports single-line and multi-line input, password fields, and real-time validation.

It consists of an internal :class:MorphTextInput for handling text input and additional widgets for labels, supporting text, and icons. These child widgets are managed internally and can be customized or replaced as needed. The main child widgets include: - :attr:heading_widget: Internal widget for the main label of the text field. It displays the primary label that describes the purpose of the text field. - :attr:supporting_widget: Displays supporting text for the text field. This is typically used to show error messages or additional information. - :attr:tertiary_widget: Displays the current text length and character count for the text field. - :attr:leading_icon_widget: Displays a leading icon for the text field. This icon is positioned at the start of the text field and can be used to indicate the purpose of the text field or provide visual context. - :attr:trailing_icon_widget: Displays a trailing icon for the text field. This icon is positioned at the end of the text field and can be used to indicate additional actions or provide visual context.

The text field supports three visual styles: filled, outlined, and rounded. The default style is filled, but you can use the specific classes :class:MorphTextFieldFilled, :class:MorphTextFieldOutlined, and :class:MorphTextFieldRounded to create instances with the desired style. Each style has its own visual characteristics, such as border and background appearance, while sharing the same core functionality and properties.

Examples:

Here is an example of how to use the MorphTextField in a simple app:

```python from morphui.app import MorphApp from morphui.uix.floatlayout import MorphFloatLayout from morphui.uix.textfield import MorphTextField

class MyApp(MorphApp): def build(self) -> MorphFloatLayout: self.theme_mode='Dark' self.seed_color='morphui_teal'

    layout = MorphFloatLayout(
        MorphTextField(
            identity='text_field',
            heading_text='Enter your name',
            supporting_text='This field is required.',
            leading_icon='account',
            trailing_icon='close',
            pos_hint={'center_x': 0.5, 'center_y': 0.5},
            size_hint=(0.8, None),),
        theme_color_bindings=dict(
            normal_surface_color='background_color',),)
    self.text_field = layout.identities.text_field
    # on_release does skip animation of heading text, so using on_press instead
    self.text_field.trailing_widget.bind(on_press=self.clear_text) 
    return layout

def clear_text(self, *args) -> None:
    self.text_field.text = ''

if name == 'main': MyApp().run()

text = StringProperty('') class-attribute instance-attribute

The text content of the text field.

This property holds the current text entered in the text field. It can be accessed and modified programmatically to get or set the text value. It is bound bidirectionally to the text property of the internal :class:MorphTextInput.

:attr:text is a :class:~kivy.properties.StringProperty and defaults to ''.

disabled = BooleanProperty(False) class-attribute instance-attribute

Indicates whether the text field is disabled.

When True, the text field is disabled and does not accept input. When False, it is enabled and can receive user input. It is bound bidirectionally to the disabled property of the internal :class:MorphTextInput.

:attr:disabled is a :class:~kivy.properties.BooleanProperty and defaults to False.

focus = BooleanProperty(False) class-attribute instance-attribute

Indicates whether the text field is focused (active for input).

This property reflects the focus state of the internal text input widget. When True, the text field is active and ready to receive keyboard input. When False, it is inactive. It is bound bidirectionally to the focus state of the internal :class:MorphTextInput.

:attr:focus is a :class:~kivy.properties.BooleanProperty and defaults to False.

multiline = BooleanProperty(False) class-attribute instance-attribute

Indicates whether the text field supports multiple lines of input.

When True, the text field allows multiple lines of text input. When False, it restricts input to a single line. It is bound bidirectionally to the multiline property of the internal :class:MorphTextInput.

:attr:multiline is a :class:~kivy.properties.BooleanProperty and defaults to False.

password = BooleanProperty(False) class-attribute instance-attribute

Indicates whether the text field is a password input.

When True, the text field obscures the input text for password protection. When False, it displays the input text normally. It is bound bidirectionally to the password property of the internal :class:MorphTextInput.

:attr:password is a :class:~kivy.properties.BooleanProperty and defaults to False.

spacing = VariableListProperty([dp(4), dp(4)], length=2) class-attribute instance-attribute

The spacing between the child widgets.

This property defines the amount of space (in pixels) between the child widgets within the text field, such as the heading, supporting and text input widgets. It helps to maintain a visually appealing layout by providing consistent spacing. The spacing is defined as [horizontal_spacing, vertical_spacing].

:attr:spacing is a :class:~kivy.properties.VariableListProperty and defaults to [dp(4), dp(4)].

selected_text_color_opacity = NumericProperty(0.4) class-attribute instance-attribute

The opacity of the text selection highlight color.

:attr:selected_text_color_opacity is a :class:~kivy.properties.NumericProperty and defaults to 0.4.

supporting_error_texts = DictProperty({}) class-attribute instance-attribute

Mapping of error types to supporting error messages.

This property holds a dictionary that maps specific error types to corresponding error messages. When the text field enters an error state, the appropriate error message can be displayed based on the error type. The keys in the dictionary should match the possible values of the :attr:validator property. If you want to set a supporting text if there is no error, use the 'none' key.

:attr:supporting_error_texts is a :class:~kivy.properties.DictProperty and defaults to an empty dictionary.

maximum_height = NumericProperty(dp(100)) class-attribute instance-attribute

The maximum height of the text field.

This property limits how tall the text field can grow, even when auto-sizing is enabled. It helps maintain layout consistency.

:attr:maximum_height is a :class:~kivy.properties.NumericProperty and defaults to dp(100).

focus_animation_duration = NumericProperty(0.15) class-attribute instance-attribute

The duration of the focus animation in seconds.

This property defines how long the animation takes when the text field gains or loses focus. It affects the speed of visual transitions related to focus changes.

:attr:focus_animation_duration is a :class:~kivy.properties.NumericProperty and defaults to 0.15.

focus_animation_transition = StringProperty('out_sine') class-attribute instance-attribute

The transition type for the focus animation.

This property determines the easing function used for the focus animation. It affects the style of the animation when the text field gains or loses focus. For a list of supported transitions, refer to the Kivy documentation

:attr:focus_animation_transition is a :class:~kivy.properties.StringProperty and defaults to 'out_sine'.

heading_focus_behavior = OptionProperty('float_to_border', options=['hide', 'float_to_border', 'move_above']) class-attribute instance-attribute

Controls how the heading widget behaves when the text field gains focus.

This property determines the animation and positioning behavior of the heading widget during focus transitions:

  • 'hide': The heading disappears when the text field is focused
  • 'float_to_border': The heading moves up and floats over the border (current Material Design implementation)
  • 'move_above': The heading moves completely above the input area, pushing the input field down slightly

:attr:heading_focus_behavior is a :class:~kivy.properties.OptionProperty and defaults to 'float_to_border'.

padding = VariableListProperty([dp(4), dp(4), dp(4), dp(4)], length=4) class-attribute instance-attribute

The padding values around the text field content.

This property defines the padding space that is applied around the content of the text field. The padding is defined as [left, top, right, bottom].

:attr:padding is a :class:~kivy.properties.VariableListProperty of length 4 and defaults to [dp(4), dp(4), dp(4), dp(4)].

input_widget_padding = VariableListProperty([dp(4), dp(4), dp(4), dp(4)], length=4) class-attribute instance-attribute

The padding values around the internal input widget.

This property defines the base padding space that is applied around the internal :class:MorphTextInput widget before any adjustments for icons or other widgets. The padding is defined as [left, top, right, bottom].

:attr:input_widget_padding is a :class:~kivy.properties.VariableListProperty of length 4 and defaults to [dp(4), dp(4), dp(4), dp(4)].

input_margin = AliasProperty(_get_input_margin, None, bind=['shows_leading_icon', 'shows_trailing_icon', 'padding', 'spacing', 'heading_focus_behavior', 'engaged']) class-attribute instance-attribute

The margin values applied to the internal input widget (read-only).

This property defines the margin space that is applied around the internal input widget (e.g. TextInput for TextField or other input widgets). This margin is required for positioning the internal widgets correctly. It means that this margin is the space needed between input widget and outer frame. So that when we calculate the position of the input widget, we can use this margin to determine how much space to leave around it for positioning the other widgets. The margin is defined as (left, top, right, bottom)

:attr:input_margin is a :class:~kivy.properties.AliasProperty and defaults to (dp(4), dp(4), dp(4), dp(4)).

minimum_width = AliasProperty(_get_minimum_width, None, bind=['input_margin', '_input_min_width']) class-attribute instance-attribute

The minimum width of the text field (read-only).

This property calculates the minimum width required to accommodate the internal text input widget along with the defined padding.

:attr:minimum_width is a :class:~kivy.properties.AliasProperty and is read-only.

minimum_height = AliasProperty(_get_minimum_height, None, bind=['input_margin', '_input_height'], cache=True) class-attribute instance-attribute

The minimum height of the text field (read-only).

This property calculates the minimum height required to accommodate the internal text input widget along with the defined padding.

:attr:minimum_height is a :class:~kivy.properties.AliasProperty and is read-only.

engaged = AliasProperty(lambda self: self.focus or bool(self.text), None, bind=['focus', 'text'], cache=True) class-attribute instance-attribute

Whether the text field is active — focused or has content (read-only).

Used to drive heading animation, border state, and padding transitions. Override in subclasses to add further conditions, e.g. a date picker that treats a selected date as active even without typed text.

:attr:is_active is a :class:~kivy.properties.AliasProperty bound to focus and text.

content_bbox = AliasProperty(lambda self: [self.x + self.padding[0], self.y + self.height - self.padding[1], self.x + self.width - self.padding[2], self.y + self.padding[3]], None, bind=['pos', 'size', 'padding']) class-attribute instance-attribute

The bounding box of the content area (read-only).

This property calculates the bounding box of the content area based on the text field's position, size, and padding.

:attr:content_bbox is a :class:~kivy.properties.AliasProperty and is read-only.

input_bbox = AliasProperty(lambda self: [self.x + self.input_margin[0], self.y + self.height - self.input_margin[1], self.x + self.width - self.input_margin[2], self.y + self.input_margin[3]], None, bind=['pos', 'size', 'input_margin']) class-attribute instance-attribute

The bounding box of the internal input widget (read-only).

This property calculates the bounding box of the internal input widget based on the text field's position, size, and input margins.

:attr:input_bbox is a :class:~kivy.properties.AliasProperty and is read-only.

default_config = dict(theme_color_bindings=(dict(normal_surface_color='surface_color', normal_border_color='outline_color', error_border_color='error_color', focus_border_color='primary_color', disabled_border_color='outline_variant_color', normal_content_color='content_surface_color', error_content_color='error_color', disabled_content_color='outline_variant_color', selected_text_color='secondary_color')), size_hint_y=None) class-attribute instance-attribute

Default configuration values for MorphTextField.

Provides standard text field appearance and behavior settings: - Single-line input for concise data entry. - Rounded corners for a modern look. - Themed colors for consistency with the overall UI design.

input_widget property

The internal text input widget (read-only).

This property provides access to the internal :class:MorphTextInput widget that is used for handling user input. It allows external code to interact with the text input widget directly if needed. Internal it is used to bind properties for bidirectional updates and to set properties like padding and maximum height.

RETURNS DESCRIPTION
MorphTextInput

The internal text input widget.

selected_text_color = self.selected_text_color or self._text_input.selection_color class-attribute instance-attribute

The color of the text selection highlight.

This property defines the RGBA color used to highlight selected text within the text field. It is bound bidirectionally to the selected_text_color property of the internal :class:MorphTextInput.

:attr:selected_text_color is a :class:~kivy.properties.ColorProperty and defaults to None.

refresh_textfield_content(*args)

Refresh the content of the text field and its child widgets.

This method updates the text and icons of the child widgets by calling the _update_child_widget method for each widget.

MorphTextFieldOutlined(**kwargs)

Bases: MorphTextField

A MorphTextField with outlined style.

This class provides an outlined appearance for the text field, adhering to Material Design guidelines.

Example

```python from morphui.app import MorphApp from morphui.uix.floatlayout import MorphFloatLayout from morphui.uix.textfield import MorphTextFieldOutlined

class MyApp(MorphApp): def build(self) -> MorphFloatLayout: self.theme_mode='Dark' self.seed_color='morphui_teal'

    layout = MorphFloatLayout(
        MorphTextFieldOutlined(
            identity='text_field',
            heading_text='Enter your name',
            supporting_text='This field is required.',
            leading_icon='account',
            trailing_icon='close',
            pos_hint={'center_x': 0.5, 'center_y': 0.5},
            size_hint=(0.8, None),),
        theme_color_bindings=dict(
            normal_surface_color='background_color',),)
    self.text_field = layout.identities.text_field
    # on_release does skip animation of heading text, so using on_press instead
    self.text_field.trailing_widget.bind(on_press=self.clear_text) 
    return layout

def clear_text(self, *args) -> None:
    self.text_field.text = ''

if name == 'main': MyApp().run()

MorphTextFieldRounded(**kwargs)

Bases: MorphRoundSidesBehavior, MorphTextField

A MorphTextField with rounded sides and elevation behavior.

This class combines the features of MorphTextField with rounded sides and elevation behavior for enhanced visual appearance.

Examples:

```python from morphui.app import MorphApp from morphui.uix.floatlayout import MorphFloatLayout from morphui.uix.textfield import MorphTextFieldRounded

class MyApp(MorphApp): def build(self) -> MorphFloatLayout: self.theme_mode='Dark' self.seed_color='morphui_teal'

    layout = MorphFloatLayout(
        MorphTextFieldRounded(
            identity='text_field',
            heading_text='Enter your name',
            supporting_text='This field is required.',
            leading_icon='account',
            trailing_icon='close',
            pos_hint={'center_x': 0.5, 'center_y': 0.5},
            size_hint=(0.8, None),),
        theme_color_bindings=dict(
            normal_surface_color='background_color',),)
    self.text_field = layout.identities.text_field
    # on_release does skip animation of heading text, so using on_press instead
    self.text_field.trailing_widget.bind(on_press=self.clear_text) 
    return layout

def clear_text(self, *args) -> None:
    self.text_field.text = ''

if name == 'main': MyApp().run()

MorphTextFieldFilled(**kwargs)

Bases: MorphTextField

A MorphTextField with filled style.

This class provides a filled appearance for the text field, adhering to Material Design guidelines.

Examples:

```python from morphui.app import MorphApp from morphui.uix.floatlayout import MorphFloatLayout from morphui.uix.textfield import MorphTextFieldFilled

class MyApp(MorphApp): def build(self) -> MorphFloatLayout: self.theme_mode='Dark' self.seed_color='morphui_teal'

    layout = MorphFloatLayout(
        MorphTextFieldFilled(
            identity='text_field',
            heading_text='Enter your name',
            supporting_text='This field is required.',
            leading_icon='account',
            trailing_icon='close',
            pos_hint={'center_x': 0.5, 'center_y': 0.5},
            size_hint=(0.8, None),),
        theme_color_bindings=dict(
            normal_surface_color='background_color',),)
    self.text_field = layout.identities.text_field
    # on_release does skip animation of heading text, so using on_press instead
    self.text_field.trailing_widget.bind(on_press=self.clear_text) 
    return layout

def clear_text(self, *args) -> None:
    self.text_field.text = ''

if name == 'main': MyApp().run()