Component property reference¶
All visual and layout properties are passed via the style dict (or list of dicts) to element functions. Behavioural properties (callbacks, data, content) remain as keyword arguments.
Layout properties are interpreted by Yoga in the renderer core, with platform measurements for text and controls. Visual properties are applied by component managers. The browser preview runs the same core as WebAssembly and mounts DOM widgets. See Layout engine for the shared rules and platform differences.
Common layout properties (inside style)¶
All components accept these layout properties in their style dict:
Sizing¶
width: fixed width in dp (Android) / pt (iOS). Accepts anint/float, or a percentage string like"50%"(resolved against the parent's content width).height: fixed height. Same number / percentage rules aswidth.min_width,max_width: width constraints (numbers or"%"strings).min_height,max_height: height constraints.aspect_ratio: width / height ratio. When only one ofwidth/heightis known, the other axis is derived from this ratio.
Flex¶
flex: shorthand. Settingflex: Nis equivalent toflex_grow: N, flex_shrink: 1, flex_basis: 0.flex_grow: how much a child grows to fill remaining main-axis space.flex_shrink: how much a child shrinks when its parent runs out of space.flex_basis: initial main-axis size before grow / shrink is applied ("auto", a number, or a percentage string).align_self: override parent alignment for this child ("auto","stretch","flex_start","center","flex_end").
Spacing¶
margin: outer spacing. Accepts a number (all sides), or a dict with any ofhorizontal,vertical,left,top,right,bottom.padding: inner spacing on container elements. Same shape asmargin.gap: space between children of a flex container.row_gapandcolumn_gapset one axis.
Position¶
position:"relative"(default) or"absolute". Absolute children are removed from the normal flow and placed usingtop/right/bottom/left(numbers or percentage strings).top,right,bottom,left: offsets used whenposition: "absolute".inset,inset_horizontal,inset_vertical: shorthands that fill all four edges,leftandright, ortopandbottom; explicit edge keys win. They mirror thepadding_horizontal/padding_verticalvocabulary.
Other¶
key: stable identity for reconciliation (passed as a kwarg, not insidestyle).
Accessibility and testing (kwargs)¶
Most visible components also accept these keyword arguments (see Platform & Accessibility):
accessibility_label,accessibility_hint,accessibility_role,accessibleaccessibility_state: dict ofdisabled/selected/checked/busy/expandedflagsaccessibility_value: a string or anAccessibilityValuewithmin/max/now/textaccessibility_actionsandon_accessibility_action: custom screen-reader actions (AccessibilityAction) and the callback that receives the invoked action's nameaccessibility_live_region:"none","polite", or"assertive"important_for_accessibility:"auto","yes","no", or"no_hide_descendants"test_id: stable identifier exposed to UI test frameworks (accessibilityIdentifieron iOS, resource-id on Android)ref: aRefthat receives a typed handle after commiton_layout(views): callback receiving aLayoutEventafter layout and on frame changes
View¶
pn.View(*children, style={
"flex_direction": "column",
"justify_content": "center",
"align_items": "center",
"overflow": "hidden",
"gap": 8,
"padding": 16,
"background_color": "#F5F5F5",
})
Universal flex container (like React Native's View). Defaults to flex_direction: "column".
Flex container properties (inside style):
flex_direction:"column"(default),"row","column_reverse","row_reverse"justify_content:"flex_start","center","flex_end","space_between","space_around","space_evenly"align_items:"stretch","flex_start","center","flex_end"overflow:"visible"(default),"hidden"gap,padding,background_color
Containers also fully support absolute positioning for their children:
pn.View(
pn.View(style={"position": "absolute", "top": 0, "left": 0,
"width": 40, "height": 40, "background_color": "#F00"}),
pn.View(style={"position": "absolute", "bottom": 8, "right": 8,
"width": 40, "height": 40, "background_color": "#0A0"}),
style={"width": 200, "height": 200, "background_color": "#EEE"},
)
Text¶
pn.Text(text, ellipsize_mode="tail", selectable=False, allow_font_scaling=True,
on_press=None, style={"font_size": 18, "color": "#333", "bold": True, "text_align": "center"})
text: display string (positional)on_press: callback() -> Nonewhen the label is tapped; on a nested span, when that span is tappedellipsize_mode: where to truncate pastmax_lines:"head","middle","tail"(default), or"clip". Android draws"head"and"middle"only on single-line text.selectable: let the user select and copy the textallow_font_scaling: scale with the user's text-size setting (defaultTrue); setFalsefor text that must keep its exact size- Style properties:
font_size,color,bold,text_align,background_color,max_lines
Rich text: pass a mix of strings and nested Text elements as the
positional parts; they flatten into a single native attributed string
(each nested Text styles its own run and inherits the rest):
pn.Text("Total: ", pn.Text("$42", style={"bold": True, "color": "#16A34A"}))
pn.Text("Read the ", pn.Text("terms", on_press=open_terms, style={"color": "#06F"}), ".")
A nested Text with on_press becomes a pressable span; only nested
spans produce span presses, while on_press on the outer element is the
whole-label event.
Button¶
pn.Button(title, on_press=handler, style={"color": "#FFF", "background_color": "#007AFF", "font_size": 16})
title: button label (positional)on_press: callback() -> Noneenabled: interactive state (kwarg, defaultTrue)- Style properties:
color,background_color,font_size
Column / Row¶
pn.Column(*children, style={"gap": 12, "padding": 16, "align_items": "center"})
pn.Row(*children, style={"gap": 8, "justify_content": "space_between"})
Convenience wrappers for View with fixed flex_direction:
Column=Viewwithflex_direction: "column"(always vertical)-
Row=Viewwithflex_direction: "row"(always horizontal) -
*children: child elements (positional) - Style properties:
gap: space between children (dp / pt)padding: inner padding (int for all sides, or dict withhorizontal,vertical,left,top,right,bottom)align_items: cross-axis alignment:"stretch","flex_start","center","flex_end","leading","trailing"justify_content: main-axis distribution:"flex_start","center","flex_end","space_between","space_around","space_evenly"overflow:"visible"(default),"hidden"background_color: container background
SafeAreaView¶
Container that respects safe area insets (notch, status bar).
ScrollView¶
pn.ScrollView(
*children,
horizontal=False, # scroll along x instead of y
content_container_style={"padding": 16, "gap": 12},
content_inset=pn.EdgeInsets(bottom=80),
scroll_enabled=True,
scroll_event_throttle=16, # ms between on_scroll callbacks
on_scroll=lambda e: ..., # ScrollEvent
on_scroll_begin_drag=..., on_scroll_end_drag=..., on_momentum_scroll_end=...,
shows_scroll_indicator=True,
paging_enabled=False, # snap to viewport-sized pages (carousel)
bounces=True, # iOS rubber-band overscroll
keyboard_dismiss_mode=None, # "none" | "on_drag" | "interactive"
keyboard_should_persist_taps="never", # "never" | "always" | "handled"
snap_to_interval=None, snap_to_alignment="start",
deceleration_rate="normal", # "normal" | "fast" | a float
refresh_control=pn.RefreshControl(refreshing=loading, on_refresh=reload),
ref=scroll_ref, # receives a ScrollViewHandle
style={"background_color": "#FFF"},
)
horizontal: scroll along the x axis instead of the y axiscontent_container_style: style for the scrollable content (padding, gap, alignment), distinct fromstyle(the scroll frame). The children are wrapped in one innerViewcarrying this style, so every layout key works on every renderer.content_inset: extra scrollable space around the content, as anEdgeInsetsscroll_enabled: whenFalse, the user can't scroll (imperative scrolling still works)scroll_event_throttle: minimum milliseconds betweenon_scrollcallbacks; native emitson_scrollonly when the app wired iton_scroll,on_scroll_begin_drag,on_scroll_end_drag,on_momentum_scroll_end: callbacks receiving aScrollEvent(x,y,content_width,content_height,viewport_width,viewport_height)shows_scroll_indicator: show/hide the scroll barpaging_enabled: snap scrolling to multiples of the viewport sizebounces: enable the iOS overscroll bouncekeyboard_dismiss_mode:"none","on_drag", or"interactive"keyboard_should_persist_taps: whether a tap inside the scroll view dismisses the keyboard:"never"(default),"always", or"handled"snap_to_interval,snap_to_alignment: snap the resting offset to multiples of a length, aligned to"start","center", or"end"deceleration_rate:"normal","fast", or a per-millisecond factor (0.998is normal,0.99is fast)refresh_control: pull-to-refresh element (seeRefreshControl)ref: receives aScrollViewHandle(scroll_to,scroll_to_end,flash_scroll_indicators,await get_scroll_offset())
TextInput¶
pn.TextInput(value="", placeholder="Enter text", on_change=handler, secure=False,
editable=True, clear_button=True, on_focus=f, on_blur=g,
selection=(start, end), on_selection_change=lambda e: ...,
on_key_press=lambda e: ..., on_content_size_change=lambda e: ...,
select_text_on_focus=False, blur_on_submit=None,
keyboard_type="default", keyboard_appearance="default",
selection_color="#007AFF", text_content_type="password",
ref=input_ref,
style={"font_size": 16, "color": "#000", "background_color": "#FFF"})
on_change: callback(str) -> Nonereceiving new texton_submit: callback(str) -> Noneon Return / Doneselection: controlled selection as(start, end)UTF-16 offsets;start == endplaces the careton_selection_change: callback receiving aSelectionEvent(start,end)on_key_press: callback receiving aKeyPressEventwhosekeyis the typed character or"Backspace"/"Enter". iOS and Android report only what their input pipeline exposes; the browser reports every key.on_content_size_change: callback receiving aContentSizeEvent(width,height) when the measured text size changes (auto-growing multiline fields)select_text_on_focus: select the whole text when the field gains focusblur_on_submit: whether submitting blurs the field;None(default) blurs single-line fields and keeps multiline fields focusedkeyboard_type: aKeyboardType:"default","email_address","number_pad","decimal_pad","phone_pad","url","ascii","numbers_and_punctuation","web_search", or"visible_password"keyboard_appearance: iOS keyboard theme,"default","light", or"dark"; ignored elsewhereeditable: whenFalse, the field is read-onlyclear_button: show an inline clear ("x") button while editingon_focus/on_blur: callbacks() -> Noneon focus changesselection_color: cursor / selection highlight colortext_content_type: autofill hint ("username","password","one_time_code", ...)ref: receives aTextInputHandle(focus,blur,clear,select_all,set_selection,await get_value())- Other kwargs:
secure,multiline,auto_capitalize,auto_correct,auto_focus,return_key_type,max_length,placeholder_color
Image¶
pn.Image(source="https://example.com/photo.jpg",
placeholder_color="#E2E8F0",
on_load_start=lambda: ..., on_load=lambda e: ..., on_load_end=lambda: ...,
on_error=lambda message: ...,
fade_duration=200, headers={"Authorization": f"Bearer {token}"},
scale_type="cover", style={"width": 200, "height": 150})
source: a bundledAsset, an image URL (http://.../https://...), an inlinedata:URI, or an absolute file pathplaceholder_color: background shown while a remote image loadson_load_start: callback() -> Nonewhen loading beginson_load: callback receiving anImageLoadEvent(width,height) once the image is displayedon_load_end: callback() -> Noneafteron_loadoron_erroron_error: callback(str) -> Nonewhen loading or decoding failsfade_duration: milliseconds to cross-fade the image in (Android and the browser; iOS shows it at once)headers: extra HTTP headers sent with a networksource- Style properties:
width,height,scale_type("cover","contain","stretch","center"),background_color,tint_color
Remote sources load through the shared image pipeline: background download, memory + disk caching, request deduplication, and decode downsampled to the view's bounds.
Switch¶
on_change: callback(bool) -> None
Slider¶
on_change: callback(float) -> None
ProgressBar¶
value: 0.0 to 1.0color: color of the filled portiontrack_color: color of the unfilled trackindeterminate: animate continuously and ignorevalue
ActivityIndicator¶
animating: hide the spinner whenFalsecolor: spinner colorsize:"small"(default) or"large"
WebView¶
pn.WebView(
url="https://example.com",
html=None, # render inline HTML instead of a URL
on_load=lambda url: ..., # page finished loading
on_message=lambda msg: ..., # window.pythonnative.postMessage(...)
on_navigation_state_change=lambda url: ...,
inject_javascript="document.body.style.background='#fff'",
scroll_enabled=True,
)
url: page to load (ignored whenhtmlis given)html: inline HTML markupon_load: callback(url) -> Nonewhen a page finishes loadingon_message: callback(str) -> Nonefor messages posted from page JSon_navigation_state_change: callback(url) -> Noneon navigationinject_javascript: JS evaluated after each page loadscroll_enabled: allow scrolling within the web content
Spacer¶
size: fixed dimension in dp / ptflex: flex grow factor
Pressable¶
pn.Pressable(child, on_press=handler, on_long_press=handler,
disabled=False, delay_long_press=500,
android_ripple=pn.Ripple(color="#33000000"))
Wraps any child element with tap/long-press handling.
disabled: whenTrue, no press callback fires and the view reports the disabled accessibility statedelay_long_press: milliseconds a press must be held beforeon_long_pressfires (default 500)pressed_opacity: opacity applied while the finger is down (default 0.6)android_ripple: aRipple(color,borderless,radius,foreground) drawn on Android while pressed; ignored on iOS and in the browserhit_slop,gestures,on_layout: as onView
style and the single child may also be callables receiving a
PressState, re-evaluated as the press state
changes:
pn.Pressable(
lambda state: pn.Text("Pressed" if state.pressed else "Press me"),
on_press=handler,
style=lambda state: {"opacity": 0.6 if state.pressed else 1.0},
)
Modal¶
pn.Modal(*children, visible=show_modal, on_dismiss=handler, on_show=shown,
on_request_close=lambda: set_show_modal(False),
title="Confirm", animation_type="slide", transparent=False,
presentation_style="page_sheet", dismiss_on_backdrop=True,
status_bar_translucent=False,
style={"background_color": "#FFF"})
Overlay dialog shown when visible=True.
on_dismiss: callback() -> Noneonce the modal has closed aftervisiblebecameFalseon_show: callback() -> Noneonce the modal finishes presentingon_request_close: callback() -> Nonewhen the user asks to close the modal from outside your content (the Android back button, an iOS sheet pull-down, or a tap on an overlay's backdrop); setvisible=Falsein response. When unset, the modal stays open.status_bar_translucent: draw the modal under a translucent status bar (Android only)animation_type:"slide"(default),"fade","none"transparent: dim the underlying view instead of fully covering itpresentation_style:"page_sheet"(default),"form_sheet","full_screen","overlay"dismiss_on_backdrop: whenTrue(default), a tap on the dimmed backdrop of a transparent or"overlay"modal, outside its content, callson_request_close;Falseignores those taps and locks an iOS sheet against the pull-down
StatusBar¶
pn.StatusBar(bar_style="light", background_color="#000000", hidden=False,
translucent=False, animated=False)
Side-effect element that configures the device status bar; it renders nothing visible.
bar_style:"light","dark", or"default"background_color: status-bar background (Android only)hidden: hide the status bartranslucent: draw content under the status bar instead of below it (Android only; iOS always draws underneath)animated: animatebar_styleandhiddenchanges (iOS only)
TouchableOpacity¶
pn.TouchableOpacity(child, on_press=handler, on_long_press=handler,
active_opacity=0.2, disabled=False)
Tappable wrapper that dips to active_opacity while pressed (a thin alias
over Pressable). disabled=True ignores presses and dims the
content.
ImageBackground¶
pn.ImageBackground(child, source="bg.png", scale_type="cover",
style={"width": 320, "height": 180, "padding": 16})
Renders child content layered over a background image. Composed from an
absolutely-filled Image plus a content View.
source: image resource name or URLscale_type:"cover"(default),"contain","stretch","center"
Checkbox¶
pn.Checkbox(value=accepted, on_change=set_accepted, label="Accept terms",
disabled=False, color="#007AFF")
value: checked state (bool)on_change: callback(bool) -> Nonelabel: optional inline label (also tappable)disabled: grey out and ignore inputcolor: tint for the checked box
| Platform | Native view |
|---|---|
| Android | android.widget.CheckBox |
| iOS | checkmark UIButton |
SegmentedControl¶
pn.SegmentedControl(segments=["Day", "Week", "Month"], selected_index=0,
on_change=handler, tint_color="#007AFF")
segments: list of segment label stringsselected_index: index of the selected segmenton_change: callback(int) -> Nonewith the new indextint_color: accent color for the selected segment
| Platform | Native view |
|---|---|
| Android | toggle row (LinearLayout of buttons) |
| iOS | UISegmentedControl |
DatePicker¶
pn.DatePicker(value="2026-05-31", mode="date", on_change=handler,
minimum="2026-01-01", maximum="2026-12-31")
ISO-8601 string values: "YYYY-MM-DD" (date), "HH:MM" (time),
"YYYY-MM-DDTHH:MM" (datetime).
value: current selection (ISO-8601 string)mode:"date"(default),"time","datetime"on_change: callback(str) -> Nonewith the new ISO-8601 stringminimum/maximum: selectable bounds
| Platform | Native view |
|---|---|
| Android | DatePickerDialog / TimePickerDialog |
| iOS | UIDatePicker |
Picker¶
pn.Picker(value=selected, items=[{"value": "a", "label": "Apple"}],
on_change=handler, placeholder="Select…")
Native dropdown / select. items is a list of {"value": Any, "label": str}.
RefreshControl¶
pn.ScrollView(child, refresh_control=pn.RefreshControl(
refreshing=loading, on_refresh=reload, tint_color="#007AFF"))
Pull-to-refresh control, an element of type "RefreshControl", passed as the refresh_control= prop of a ScrollView, FlatList, or SectionList. The scroll container attaches it to its native scroll view rather than rendering it as a child, and raises TypeError for anything that isn't a RefreshControl.
refreshing: drive the spinner from stateon_refresh: callback() -> Nonewhen pulled past thresholdtint_color: spinner color
TabBar¶
pn.Element("TabBar", {
"items": [
{"name": "Home", "title": "Home"},
{"name": "Settings", "title": "Settings"},
],
"active_tab": "Home",
"on_tab_select": handler,
})
Native tab bar, typically created automatically by a
TabNavigator.
| Platform | Native view |
|---|---|
| Android | BottomNavigationView |
| iOS | UITabBar |
items: list of{"name": str, "title": str}dicts defining each tabactive_tab: thenameof the currently active tabon_tab_select: callback(str) -> Nonereceiving the selected tab name
FlatList¶
pn.FlatList(data=items, render_item=render_fn, key_extractor=key_fn,
item_height=44, separator_height=1,
horizontal=False, num_columns=1,
list_header=pn.Text("Header"), list_footer=pn.Text("Footer"),
list_empty=pn.Text("Nothing here"),
on_end_reached=load_more, on_end_reached_threshold=0.5,
refresh_control=pn.RefreshControl(refreshing=loading, on_refresh=reload),
content_container_style={"padding": 8},
style={"background_color": "#FFF"})
data: list of itemsrender_item:(item, index) -> Elementfunctionkey_extractor:(item, index) -> strfor stable keysitem_height: fixed row extent; reduces measurement work in the native RecyclerView / UICollectionView containers (see the Lists guide)separator_height: spacing between itemsitem_separator: an element, or a zero-argument function returning one, rendered after every row except the lasthorizontal: scroll horizontally; row extents become widthsinverted: render bottom-up (or right-to-left whenhorizontal), so rows appended todataappear at the visible end, as in a chatinitial_scroll_index: item index scrolled to, without animation, once the list mountsnum_columns: render as a grid of N columnson_scroll: callback receiving aScrollEventon_viewable_items_changed: callback receiving a list of{"index", "key", "item"}dicts whenever the visible rows changelist_header/list_footer: elements rendered once above / below rowslist_empty: element rendered whendatais emptyon_end_reached: callback() -> Nonenear the end (virtualized)on_end_reached_threshold: fraction-of-viewport trigger distancecontent_container_style: style for the inner content wrapperrefresh_control: pull-to-refresh element (seeRefreshControl)ref: receives aListController
SectionList¶
pn.SectionList(sections=[pn.Section(key="a", title="A", data=["Apple"])],
render_item=lambda item, i, s: pn.Text(item),
render_section_header=lambda section, s: pn.Text(section.title),
sticky_section_headers=True, inverted=False,
item_separator=lambda: pn.View(style={"height": 1, "background_color": "#EEE"}),
on_viewable_items_changed=handler)
Virtualized list with section headers interleaved between row groups;
shares the windowing engine and most arguments with FlatList.
sections: list of{"title": ..., "data": [...]}dictsrender_item:(item, item_index, section_index) -> Elementrender_section_header:(section, section_index) -> Elementsticky_section_headers: keep the current section's header pinned at the top while its items scroll by (rendered by Python as an overlay)inverted: render bottom-upitem_separator: rendered between the items of each section, never after a header or a section's last itemon_viewable_items_changed: callback receiving{"index", "key", "item"}dicts for the visible items (flat indices)