Textualize/textual · error · KeyError

No {name!r} key in COMPONENT_CLASSES

Error message

No {name!r} key in COMPONENT_CLASSES

What it means

get_component_styles raises KeyError when asked for a component style name that is not listed in the widget's COMPONENT_CLASSES. Textual requires every component class referenced in code (or matched from CSS like `-border` styling hooks) to be declared up-front so styles can be resolved.

Source

Thrown at src/textual/dom.py:618

    def get_component_styles(self, *names: str) -> RenderStyles:
        """Get a "component" styles object (must be defined in COMPONENT_CLASSES classvar).

        Args:
            names: Names of the components.

        Raises:
            KeyError: If the component class doesn't exist.

        Returns:
            A Styles object.
        """

        styles = RenderStyles(self, Styles(), Styles())

        for name in names:
            if name not in self._component_styles:
                raise KeyError(f"No {name!r} key in COMPONENT_CLASSES")
            component_styles = self._component_styles[name]
            assert component_styles.node is not None
            styles._update_node(component_styles.node)
            styles.base.merge(component_styles.base)
            styles.inline.merge(component_styles.inline)
            styles._updates += 1

        return styles

    def _post_mount(self):
        """Called after the object has been mounted."""
        _rich_traceback_omit = True
        Reactive._initialize_object(self)

    def notify_style_update(self) -> None:
        """Called after styles are updated.

        Implement this in a subclass if you want to clear any cached data when the CSS is reloaded.

View on GitHub (pinned to 06dbeef4bb)

Solutions

  1. Add the component class string to the widget's COMPONENT_CLASSES = [...] class variable exactly as referenced
  2. Fix typos/dashes in the name passed to get_component_styles so it matches an existing COMPONENT_CLASSES entry
  3. If subclassing a built-in widget, remember COMPONENT_CLASSES must be re-declared/extended since it is not inherited additively

Example fix

# before
class MyWidget(Static):
    def render_style(self):
        return self.get_component_styles('mywidget--accent')

# after
class MyWidget(Static):
    COMPONENT_CLASSES = {'mywidget--accent'}
    def render_style(self):
        return self.get_component_styles('mywidget--accent')
Defensive patterns

Strategy: validation

Validate before calling

name = 'mywidget--accent'
if name not in self._component_styles:
    # or: name not in getattr(type(self), 'COMPONENT_CLASSES', ())
    raise LookupError(f'{name!r} missing from COMPONENT_CLASSES')
styles = self.get_component_styles(name)

Type guard

def has_component_class(widget, name: str) -> bool:
    return name in widget._component_styles

Try / catch

try:
    styles = self.get_component_styles('mywidget--accent')
except KeyError as e:
    styles = RenderStyles(self, Styles(), Styles())  # graceful default

Prevention

When it happens

Trigger: Calling self.get_component_styles('foo--bar') where 'foo--bar' is not in the widget's COMPONENT_CLASSES list; CSS referencing a component class the widget never declared; copying CSS between widget types with mismatched COMPONENT_CLASSES.

Common situations: Typos or renaming a component class in CSS but not in COMPONENT_CLASSES; creating a custom widget subclass and forgetting to extend COMPONENT_CLASSES; version upgrades that rename component classes (e.g. tabs, buttons).

Related errors


AI-assisted analysis of Textualize/textual@06dbeef4bb (2026-08-27). Data as JSON: /api/errors/74d6013d273136e6. Report an issue: GitHub.