Skip to content

SDK

pythonnative.sdk is the public extension API for adding new native widgets to PythonNative. It re-exports the Element descriptor, the ViewHandler protocol, and the typed style primitives so plugin authors only need a single import path. The reference here documents the symbols that are unique to the SDK module — the re-exports are documented on their canonical pages and linked below.

The full walkthrough lives in Custom native components; this page is the symbol-level reference.

Re-exports

The following names are re-exported from pythonnative.sdk for convenience and are documented on their canonical pages:

Symbol Defined in
Element Element
ViewHandler Native views
Style, StyleProp, Color, Dimension, EdgeInsets, EdgeValue, FlexDirection, JustifyContent, Overflow, Position, TransformSpec, style Style
parse_color_int, resolve_padding pythonnative.native_views.base

Custom-component primitives

Public extension surface for PythonNative.

The pythonnative.sdk package collects the stable extension contract that third-party packages rely on: the ViewHandler protocol, the Style type, the @native_component registration decorator, and an element_factory helper for producing strongly-typed element constructors.

A custom native component is three things:

  1. A typed, frozen Props dataclass listing the public properties the component accepts.
  2. One or more ViewHandler subclasses (one per target platform) implementing creation, update, and child management for the underlying native widget.
  3. A registration call (the @native_component decorator, or register_component for imperative use) that binds the props type and handler into the process-wide registry.

Once registered, the component appears alongside the built-ins: the reconciler, layout engine, and Fast Refresh treat it identically.

PyPI packages can ship handlers without users importing them explicitly by declaring an entry point in the pythonnative.handlers group; PythonNative discovers and imports those modules the first time the registry is asked for a handler.

Example
from dataclasses import dataclass
import pythonnative as pn
from pythonnative.sdk import (
    Props,
    ViewHandler,
    element_factory,
    native_component,
)


@dataclass(frozen=True)
class BadgeProps(Props):
    text: str = ""
    color: str = "#FF3B30"
    style: pn.StyleProp = None


@native_component("Badge", props=BadgeProps, platforms=("ios",))
class IOSBadgeHandler(ViewHandler):
    def create(self, props):
        ...

    def update(self, view, changed):
        ...


Badge = element_factory("Badge")

@pn.component
def App():
    return pn.Column(
        Badge(text="3", color="#0A84FF"),
        pn.Text("Inbox"),
    )

Classes:

Name Description
Props

Optional base class for typed prop dataclasses.

Functions:

Name Description
native_component

Decorator that registers a ViewHandler under name.

register_component

Register a custom native component imperatively.

unregister_component

Remove a previously-registered component (primarily for tests).

element_factory

Return a callable that builds Element instances of type name.

install_into_registry

Copy registered handlers into a NativeViewRegistry.

list_components

Return the names of every registered custom component.

get_props_type

Return the registered props dataclass for name (or None).

Attributes:

Name Type Description
ENTRY_POINT_GROUP

Entry-point group used by PyPI packages to register native handlers.

ENTRY_POINT_GROUP module-attribute

ENTRY_POINT_GROUP = 'pythonnative.handlers'

Entry-point group used by PyPI packages to register native handlers.

Packages declare entries like:

[project.entry-points."pythonnative.handlers"]
my_blur = "my_pkg.blur:register"

PythonNative imports the referenced module the first time the NativeViewRegistry is materialized; the decorators inside that module populate the registry during import.

Props dataclass

Props()

Optional base class for typed prop dataclasses.

Subclassing is not strictly required (any @dataclass(frozen=True) works), but inheriting from Props gives third-party components a clear, searchable marker in their public API and a stable place to add framework-wide behavior in the future.

Example
from dataclasses import dataclass
from pythonnative.sdk import Props

@dataclass(frozen=True)
class BadgeProps(Props):
    text: str = ""
    color: str = "#FF3B30"

native_component

native_component(name: str, *, props: Optional[type] = None, platforms: Optional[Tuple[str, ...]] = None) -> Callable[[Type[H]], Type[H]]

Decorator that registers a ViewHandler under name.

The handler class is instantiated immediately and stored in the process-wide registry. Decorate the same name once per platform when shipping platform-specific implementations; the decorator accumulates entries in a {platform: handler} mapping per name.

Parameters:

Name Type Description Default
name str

Element type name (e.g., "Badge"). Must be a valid identifier-like string. Used by the reconciler at lookup time.

required
props Optional[type]

Optional dataclass type describing the component's typed props. When supplied, the element_factory helper uses this type to validate kwargs and produce frozen prop instances.

None
platforms Optional[Tuple[str, ...]]

Tuple of platform identifiers ("ios" / "android") the handler implements. Defaults to ("android", "ios") so a single cross-platform handler registers everywhere.

None

Returns:

Type Description
Callable[[Type[H]], Type[H]]

A decorator that, when applied to a

Callable[[Type[H]], Type[H]]

ViewHandler subclass, registers

Callable[[Type[H]], Type[H]]

it and returns the class unchanged.

Raises:

Type Description
TypeError

If the decorated object is not a class subclassing ViewHandler.

Example
from dataclasses import dataclass
from pythonnative.sdk import Props, ViewHandler, native_component


@dataclass(frozen=True)
class BadgeProps(Props):
    text: str = ""
    color: str = "#FF3B30"


@native_component("Badge", props=BadgeProps, platforms=("ios",))
class IOSBadgeHandler(ViewHandler):
    def create(self, props):
        ...

register_component

register_component(*, name: str, props: Optional[type] = None, handlers: Dict[str, ViewHandler]) -> None

Register a custom native component imperatively.

Equivalent to applying @native_component one or more times, but useful when constructing handlers programmatically (e.g., parameterized handler instances). Subsequent calls for the same name merge their handlers into the existing entry, replacing any previously-registered handler for the same platform.

Parameters:

Name Type Description Default
name str

Element type name.

required
props Optional[type]

Optional dataclass type describing the typed props.

None
handlers Dict[str, ViewHandler]

{platform_name: handler_instance} mapping. Common keys are "ios" and "android".

required

Raises:

Type Description
TypeError

If any handler is not a ViewHandler instance, or if props is not a dataclass type.

unregister_component

unregister_component(name: str) -> None

Remove a previously-registered component (primarily for tests).

Parameters:

Name Type Description Default
name str

The element type name to unregister.

required

element_factory

element_factory(name: str) -> Callable[..., Element]

Return a callable that builds Element instances of type name.

The returned factory accepts:

  • Children as positional arguments (any number).
  • key= (optional, keyword-only) for keyed reconciliation.
  • Either props= (a dataclass instance) or per-field keyword arguments matching the registered props dataclass.

If no props dataclass was registered for name, kwargs flow through unmodified — useful when iterating before locking down a prop schema.

Parameters:

Name Type Description Default
name str

An element type name previously registered via @native_component or register_component.

required

Returns:

Type Description
Callable[..., Element]

A callable producing fresh

Callable[..., Element]

Element instances of type name.

Raises:

Type Description
KeyError

If name is not registered.

Example
Badge = element_factory("Badge")
Badge(text="3", color="#0A84FF")
Badge(props=BadgeProps(text="3"))

install_into_registry

install_into_registry(registry: Any, platform_name: str) -> None

Copy registered handlers into a NativeViewRegistry.

Called once by the registry on first use. Triggers entry-point discovery on the first call so PyPI-installed handlers register themselves before the registry snapshot is taken.

Parameters:

Name Type Description Default
registry Any

A NativeViewRegistry (or duck-compatible object) with a register(name, handler) method.

required
platform_name str

The active platform identifier ("ios" or "android").

required

list_components

list_components() -> List[str]

Return the names of every registered custom component.

Useful for diagnostics and tests.

Returns:

Type Description
List[str]

Sorted list of names registered via

List[str]
List[str]

get_props_type

get_props_type(name: str) -> Optional[type]

Return the registered props dataclass for name (or None).

Entry-point discovery

Third-party packages can register handlers automatically by exposing an entry point in the pythonnative.handlers group (the value of ENTRY_POINT_GROUP). The first call to get_registry() loads every registered entry point exactly once. A misbehaving plugin raises an exception that is caught and logged; it never breaks PythonNative startup.

# In your plugin's pyproject.toml
[project.entry-points."pythonnative.handlers"]
my_widget = "my_pkg:register"

The function pointed at by the entry point should perform whatever imports are needed to call @native_component or register_component.

Next steps