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 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 Style type, the @native_component / register_component registration helpers, the element_factory helper for producing strongly-typed element constructors, the ViewHandler protocol for off-device stand-ins, and the native module registry (native_module, register_python_module).

A custom native component is three things:

  1. A typed, frozen Props dataclass listing the public properties the component accepts.
  2. A Swift PNComponentManager and a Kotlin ComponentManager registered under the component's name by the package's native plugin (pn_plugin.json next to ios/ and android/ source folders; see docs/guides/custom-components.md).
  3. A registration call in Python (register_component, or the @native_component decorator when you also supply a test ViewHandler for the Python backend) that declares the element name and binds its props type.

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

A native module (device API without a view) follows the same split: a Swift / Kotlin class registered by name in the plugin, a Python facade that calls native_module(name).call(...), and optionally a Python implementation registered with register_python_module for the browser preview and tests.

PyPI packages can ship both without users importing them explicitly by declaring entry points in the pythonnative.handlers (Python side) and pythonnative.plugins (native source) groups; pn build compiles the native sources into the app.

Example
from dataclasses import dataclass
import pythonnative as pn
from pythonnative.sdk import Props, element_factory, register_component


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


register_component(name="Badge", props=BadgeProps)
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 test 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 test handlers into a view registry.

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: tuple[str, ...] = ("ios", "android")
) -> Callable[[Type[H]], Type[H]]

Decorator that registers a test ViewHandler under name.

The handler class is instantiated immediately and stored in the process-wide registry as the component's off-device renderer. The on-device renderers are the Swift and Kotlin component managers the package's native plugin registers under the same name.

Parameters:

Name Type Description Default
name str

Element type name (e.g., "Badge"). Used by the reconciler and by native component managers 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 tuple[str, ...]

Platforms with an actual renderer for this component.

('ios', 'android')

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.

register_component

register_component(
    *,
    name: str,
    props: Optional[type] = None,
    handler: Optional[ViewHandler] = None,
    platforms: tuple[str, ...] = ("ios", "android")
) -> None

Register a custom native component imperatively.

Declares name as an element type so element_factory can build it. handler is the optional test renderer; native rendering always comes from the platform component managers. Subsequent calls for the same name merge: a later props or handler replaces the earlier one, None leaves it alone.

Parameters:

Name Type Description Default
name str

Element type name.

required
props Optional[type]

Optional dataclass type describing the typed props.

None
handler Optional[ViewHandler]

Optional ViewHandler instance used off device.

None
platforms tuple[str, ...]

Platforms with an actual renderer. Browser placeholders don't count as native support.

('ios', 'android')

Raises:

Type Description
TypeError

If 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) -> None

Copy registered test handlers into a view registry.

Called once by the registry on first use. Triggers entry-point discovery on the first call so PyPI-installed components 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

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