> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/nvaccess/nvda/llms.txt
> Use this file to discover all available pages before exploring further.

# NVDA Objects

> Understanding NVDA's object system for representing GUI controls

NVDA Objects are the fundamental building blocks that represent controls and GUI elements in NVDA. Every widget, regardless of its underlying API, is represented as an NVDAObject instance.

## What is an NVDA Object?

An NVDA Object provides:

* **Standardized properties**: name, role, value, states, description
* **Navigation**: parent, children, next, previous relationships
* **Event handling**: Response to focus, value changes, etc.
* **Scripting**: Custom commands and gesture bindings
* **Text access**: Through TextInfo objects

<CodeGroup>
  ```python Accessing Object Properties theme={null}
  import api

  # Get the current focus object
  focusObj = api.getFocusObject()

  # Access standard properties
  name = focusObj.name
  role = focusObj.role
  value = focusObj.value
  states = focusObj.states
  description = focusObj.description

  # Get location on screen
  location = focusObj.location  # (left, top, width, height)
  ```

  ```python Navigation Properties theme={null}
  # Navigate the object hierarchy
  parent = focusObj.parent
  firstChild = focusObj.firstChild
  lastChild = focusObj.lastChild
  nextSibling = focusObj.next
  previousSibling = focusObj.previous

  # Get all children
  children = focusObj.children

  # Simplified navigation (filters useless objects)
  simpleParent = focusObj.simpleParent
  simpleNext = focusObj.simpleNext
  simpleFirstChild = focusObj.simpleFirstChild
  ```
</CodeGroup>

## Base Class: NVDAObject

The `NVDAObject` class is defined in `source/NVDAObjects/__init__.py`:

```python NVDAObject base class theme={null}
class NVDAObject(
    documentBase.TextContainerObject,
    baseObject.ScriptableObject,
    metaclass=DynamicNVDAObjectType,
):
    """NVDA's representation of a single control/widget.
    
    Every widget, regardless of how it is exposed by an application or 
    the operating system, is represented as a single NVDAObject instance.
    """
    
    cachePropertiesByDefault = True
    TextInfo = NVDAObjectTextInfo
    
    # Core properties implemented via auto-property pattern
    def _get_name(self) -> str:
        """The label or name of this object"""
        return ""
    
    def _get_role(self) -> controlTypes.Role:
        """The role or type of control"""
        return controlTypes.Role.UNKNOWN
    
    def _get_value(self) -> str:
        """The value of the control"""
        return ""
    
    def _get_states(self) -> Set[controlTypes.State]:
        """Set of state constants"""
        return set()
```

## API Classes

NVDA supports multiple accessibility APIs through specialized classes:

### IAccessible Objects

For MSAA/IAccessible controls:

```python IAccessible Example theme={null}
from NVDAObjects.IAccessible import IAccessible

class CustomButton(IAccessible):
    def _get_name(self):
        # Override name from IAccessible
        return self.IAccessibleObject.accName(self.IAccessibleChildID) or "Unnamed"
    
    def _get_role(self):
        return controlTypes.Role.BUTTON
```

### UI Automation Objects

For modern Windows UIA controls:

```python UIA Example theme={null}
from NVDAObjects.UIA import UIA

class CustomEdit(UIA):
    def _get_value(self):
        # Access UIA properties
        return self.UIAElement.CurrentValue
    
    def _get_states(self):
        states = super()._get_states()
        if self.UIAElement.CurrentIsReadOnly:
            states.add(controlTypes.State.READONLY)
        return states
```

### Window Objects

For direct Win32 window access:

```python Window Example theme={null}
from NVDAObjects.window import Window

class CustomWindow(Window):
    def _get_name(self):
        # Access window properties
        return self.windowText or "Untitled"
    
    @property
    def windowClassName(self):
        return self._windowClassName
    
    @property
    def windowControlID(self):
        return self._windowControlID
```

## Dynamic Class Creation

One of NVDA's most powerful features is dynamic class creation. When an object is instantiated:

```python Dynamic class creation flow theme={null}
class DynamicNVDAObjectType(baseObject.ScriptableObject.__class__):
    _dynamicClassCache = {}
    
    def __call__(self, chooseBestAPI=True, **kwargs):
        # 1. Find the best API class
        if chooseBestAPI:
            APIClass = self.findBestAPIClass(kwargs)
            if not APIClass:
                return None
        
        # 2. Instantiate the API class
        obj = APIClass.__new__(APIClass, **kwargs)
        obj.__init__(**kwargs)
        
        # 3. Build overlay class list
        clsList = []
        obj.findOverlayClasses(clsList)
        
        # 4. Let app module choose classes
        if obj.appModule:
            obj.appModule.chooseNVDAObjectOverlayClasses(obj, clsList)
        
        # 5. Let global plugins choose classes
        for plugin in globalPluginHandler.runningPlugins:
            plugin.chooseNVDAObjectOverlayClasses(obj, clsList)
        
        # 6. Construct dynamic class
        bases = tuple(optimized_bases)
        name = "Dynamic_" + "_".join([x.__name__ for x in clsList])
        newCls = type(name, bases, {"__module__": __name__})
        
        # 7. Mutate object to new class
        obj.__class__ = newCls
        
        # 8. Initialize overlay classes
        for cls in reversed(newCls.__mro__):
            if hasattr(cls, 'initOverlayClass'):
                cls.initOverlayClass(obj)
        
        return obj
```

<Info>
  This allows NVDA to combine generic API support with application-specific behaviors without modifying core code.
</Info>

## Creating Custom NVDA Objects

### Step 1: Define the Class

Inherit from the appropriate base class:

```python Custom NVDA Object theme={null}
from NVDAObjects.IAccessible import IAccessible
from scriptHandler import script
import ui
import controlTypes

class EnhancedEditField(IAccessible):
    """Custom edit field with additional functionality"""
    
    def _get_name(self):
        # Customize the name
        return f"Enhanced: {super().name}"
    
    def _get_description(self):
        # Add helpful description
        return f"Length: {len(self.value)} characters"
    
    @script(gesture="kb:NVDA+l")
    def script_reportLength(self, gesture):
        """Report the length of text in this field"""
        length = len(self.value) if self.value else 0
        ui.message(f"{length} characters")
    
    def initOverlayClass(self):
        """Called when this overlay is applied to an object"""
        # Perform initialization
        pass
```

### Step 2: Choose When to Use It

In your app module or global plugin:

```python Choosing overlay classes theme={null}
import appModuleHandler
from NVDAObjects.IAccessible import IAccessible
import controlTypes

class AppModule(appModuleHandler.AppModule):
    
    def chooseNVDAObjectOverlayClasses(self, obj, clsList):
        """Choose custom classes for objects in this app"""
        # Check if this is an edit field we want to enhance
        if (
            isinstance(obj, IAccessible) and
            obj.role == controlTypes.Role.EDITABLETEXT and
            obj.windowClassName == "Edit"
        ):
            # Insert our custom class at the beginning
            clsList.insert(0, EnhancedEditField)
```

<Tip>
  Insert custom classes at index 0 so they are resolved first in the method resolution order (MRO).
</Tip>

## Common Properties

### Essential Properties

```python Essential properties theme={null}
class MyObject(NVDAObject):
    def _get_name(self) -> str:
        """Label of the control (e.g., button text)"""
        return "OK"
    
    def _get_role(self) -> controlTypes.Role:
        """Type of control"""
        return controlTypes.Role.BUTTON
    
    def _get_value(self) -> str:
        """Current value (e.g., slider position, checkbox state)"""
        return "50%"
    
    def _get_states(self) -> Set[controlTypes.State]:
        """Set of states"""
        states = set()
        states.add(controlTypes.State.FOCUSABLE)
        states.add(controlTypes.State.FOCUSED)
        return states
    
    def _get_description(self) -> str:
        """Description (usually from tooltip)"""
        return "Click to confirm"
```

### Location and Visibility

```python Location properties theme={null}
    def _get_location(self) -> Tuple[int, int, int, int]:
        """Screen coordinates (left, top, width, height)"""
        return (100, 100, 200, 50)
    
    def _get_hasIrrelevantLocation(self) -> bool:
        """True if object is offscreen or invisible"""
        return False
    
    def _get_presentationType(self):
        """How this object should be presented"""
        return self.presType_content  # or presType_layout
```

### Navigation Properties

```python Navigation properties theme={null}
    def _get_parent(self) -> Optional['NVDAObject']:
        """Parent object in hierarchy"""
        return self._parent
    
    def _get_firstChild(self) -> Optional['NVDAObject']:
        """First child object"""
        return self._firstChild
    
    def _get_lastChild(self) -> Optional['NVDAObject']:
        """Last child object"""
        return self._lastChild
    
    def _get_next(self) -> Optional['NVDAObject']:
        """Next sibling"""
        return self._next
    
    def _get_previous(self) -> Optional['NVDAObject']:
        """Previous sibling"""
        return self._previous
    
    def _get_children(self) -> List['NVDAObject']:
        """List of all direct children"""
        return []
```

## Working with States

States indicate the current condition of a control:

```python Using states theme={null}
import controlTypes

def processObject(obj):
    states = obj.states
    
    # Check for specific states
    if controlTypes.State.FOCUSED in states:
        print("Object has focus")
    
    if controlTypes.State.CHECKED in states:
        print("Checkbox is checked")
    
    if controlTypes.State.EXPANDED in states:
        print("Tree item is expanded")
    
    # Common states
    # FOCUSABLE, FOCUSED, SELECTED, SELECTABLE
    # CHECKED, CHECKABLE, PRESSED, EXPANDED, COLLAPSED
    # READONLY, DISABLED, INVISIBLE, OFFSCREEN
    # BUSY, LINKED, VISITED, PROTECTED
```

## Text Access

NVDA Objects can provide text access:

```python Text access theme={null}
# Get a TextInfo object
textInfo = obj.makeTextInfo(textInfos.POSITION_FIRST)

# Move and read text
textInfo.expand(textInfos.UNIT_LINE)
line_text = textInfo.text

# Get all text
storyInfo = obj.makeTextInfo(textInfos.POSITION_ALL)
all_text = storyInfo.text
```

### Custom TextInfo

```python Custom TextInfo theme={null}
from textInfos import TextInfo

class CustomTextInfo(TextInfo):
    def _getStoryText(self):
        """Return all text"""
        return self.obj.value or ""
    
    def _getStoryLength(self):
        """Return text length"""
        return len(self._getStoryText())

class MyObject(NVDAObject):
    TextInfo = CustomTextInfo
```

## Focus Redirect

Redirect focus to a different object:

```python Focus redirect theme={null}
class ContainerObject(NVDAObject):
    def _get_focusRedirect(self):
        """When this object receives focus, redirect to its first child"""
        return self.firstChild
```

## Tree Interceptors

Complex documents can have tree interceptors (like browse mode):

```python Tree interceptor theme={null}
from browseMode import BrowseModeTreeInterceptor

class MyDocument(NVDAObject):
    def _get_treeInterceptorClass(self):
        """Specify tree interceptor class"""
        return BrowseModeTreeInterceptor
    
    shouldCreateTreeInterceptor = True
```

## Practical Example: Custom Button

Complete example of a custom button with enhanced features:

```python Complete custom button example theme={null}
from NVDAObjects.IAccessible import IAccessible
from scriptHandler import script
import ui
import tones
import controlTypes

class EnhancedButton(IAccessible):
    """A button with sound effects and additional info"""
    
    def _get_name(self):
        # Add emoji to name for fun
        base_name = super().name
        return f"🔘 {base_name}"
    
    def _get_description(self):
        # Provide helpful description
        return f"Press {self.name} button to activate"
    
    def event_gainFocus(self):
        """Play sound when button receives focus"""
        tones.beep(440, 50)
        super().event_gainFocus()
    
    @script(
        gesture="kb:NVDA+b",
        description="Report button information"
    )
    def script_reportInfo(self, gesture):
        """Report detailed button information"""
        info = [
            f"Name: {self.name}",
            f"Role: {self.role}",
            f"Location: {self.location}",
            f"Window class: {self.windowClassName}",
        ]
        ui.message(", ".join(info))
    
    def initOverlayClass(self):
        """Initialize the button"""
        # Log when this overlay is applied
        log.debug(f"Enhanced button overlay applied to {self.name}")

# In app module:
class AppModule(appModuleHandler.AppModule):
    def chooseNVDAObjectOverlayClasses(self, obj, clsList):
        if obj.role == controlTypes.Role.BUTTON:
            clsList.insert(0, EnhancedButton)
```

## Best Practices

<AccordionGroup>
  <Accordion title="Property Caching">
    Properties are cached by default for performance. To disable caching for a specific property:

    ```python theme={null}
    class MyObject(NVDAObject):
        _cache_dynamicProperty = False
        
        def _get_dynamicProperty(self):
            # This will be fetched every time
            return self._getCurrentValue()
    ```
  </Accordion>

  <Accordion title="Overlay Class Order">
    Classes in `clsList` should be ordered from most specific to most general:

    ```python theme={null}
    def chooseNVDAObjectOverlayClasses(self, obj, clsList):
        # Most specific first
        clsList.insert(0, VerySpecificClass)
        # More general after
        clsList.append(GeneralClass)
    ```
  </Accordion>

  <Accordion title="Memory Management">
    NVDA uses weak references for object relationships. Don't store strong references unnecessarily:

    ```python theme={null}
    # Good - uses weak reference
    self._parentRef = weakref.ref(parent)

    # Bad - strong reference creates memory leak
    self._parent = parent
    ```
  </Accordion>

  <Accordion title="API-Specific Properties">
    Only access API-specific properties when you know the object type:

    ```python theme={null}
    from NVDAObjects.IAccessible import IAccessible

    if isinstance(obj, IAccessible):
        accName = obj.IAccessibleObject.accName(obj.IAccessibleChildID)
    ```
  </Accordion>
</AccordionGroup>

## See Also

<CardGroup cols={2}>
  <Card title="Events" icon="bolt" href="/development/architecture/events">
    Learn about event handling
  </Card>

  <Card title="Scripts & Gestures" icon="keyboard" href="/development/architecture/scripts-and-gestures">
    Add commands to objects
  </Card>

  <Card title="Writing Plugins" icon="code" href="/development/plugins">
    Create app modules and overlays
  </Card>

  <Card title="Architecture Overview" icon="sitemap" href="/development/architecture/overview">
    Understand the big picture
  </Card>
</CardGroup>
