appkit-mantine
reflex.dev components based on MantineUI
A Reflex wrapper library exposing the full Mantine UI v9.5.2 component suite — inputs, buttons, overlays, navigation, layout, data display, feedback, charts, maps, scheduling and more — for building robust, type-safe Python web applications.
✨ Features
- 🧩 Full Component Coverage - 90+ components across inputs, buttons, overlays, navigation, layout, data display, feedback, charts, maps, scheduling, and typography
- 🔒 Type-Safe - Full type annotations with IDE autocomplete support for all props and event handlers (
.pyistubs for every component) - 📚 Rich Examples - Production-ready code examples for every component with common patterns and edge cases
- 🏗️ Clean Architecture - Inheritance-based design (
MantineComponentBase→MantineLayoutComponentBase→MantineInputComponentBase) eliminating code duplication across ~40 common props - 🎨 Mantine Integration - Seamless integration with Mantine's theming, color modes, and design system;
MantineProvideris auto-injected - ⚡ Modern Stack - Built on Reflex 0.9.6+ with React 18 and Mantine 9.5.2
📦 Installation
Using pip
pip install appkit-mantine
Using uv (recommended)
uv add appkit-mantine
Development Installation
For local development or to run the demo application:
# Clone the repository
git clone https://github.com/jenreh/appkit.git
cd appkit
# Install with uv (installs workspace components)
uv sync
# Run the demo app
reflex run
🚀 Quick Start
import reflex as rx
import appkit_mantine as mn
class FormState(rx.State):
email: str = ""
password: str = ""
def login_form() -> rx.Component:
return rx.container(
rx.vstack(
rx.heading("Login"),
# Basic input with validation
mn.form.input(
label="Email",
placeholder="you@example.com",
value=FormState.email,
on_change=FormState.set_email,
required=True,
type="email",
),
# Password input with visibility toggle
mn.password_input(
label="Password",
value=FormState.password,
on_change=FormState.set_password,
required=True,
),
rx.button("Sign In", on_click=FormState.handle_login),
spacing="4",
),
max_width="400px",
)
app = rx.App()
app.add_page(login_form)
📋 Available Components
Inputs
| Component | Description | Documentation |
|---|---|---|
text_input |
Basic text input / text inputs showcase | Guide |
input |
Polymorphic base input element with sections, variants, sizes | Examples |
password_input |
Password field with visibility toggle | Examples |
number_input |
Numeric input with formatting, min/max, step controls | Examples |
textarea |
Multi-line text input with auto-resize | Guide |
json_input |
JSON input with formatting, validation, parser, pretty printing | Examples |
masked_input |
Input masking for phone numbers, credit cards, custom patterns (uncontrolled) | Guide |
color_input / color_picker |
Color entry and swatch picker | Examples |
file_input / dropzone |
File selection input and drag-and-drop upload zone | Examples |
rating, pin_input, chip, fieldset |
Additional form primitives | Examples |
checkbox, radio, switch, segmented_control |
Toggle-style inputs | Examples |
slider, range_slider, hue_slider, alpha_slider, angle_slider |
Slider family | Examples |
select, multi_select, autocomplete, combobox, tags_input, tree_select |
Selection and combobox-based inputs | Examples |
cascader |
Hierarchical select drilling down through cascading columns | Examples |
rich_select |
Advanced select component with search and grouping | Examples |
date_input, date_picker, date_picker_input, date_time_picker, time_input, time_picker, month_picker, year_picker, calendar |
Full date/time picker family | Examples |
rich_text_editor |
WYSIWYG editor powered by Tiptap | Guide |
Buttons
| Component | Description | Documentation |
|---|---|---|
action_icon |
Lightweight button for icons with size, variant, radius, disabled state | Examples |
button |
Button with variants, sizes, gradient, loading states, sections | Examples |
close_button, unstyled_button |
Additional button variants | Examples |
Overlays
| Component | Description | Documentation |
|---|---|---|
modal |
Accessible overlay dialog with focus trap and scroll lock | Examples |
drawer |
Overlay drawer area sliding from any side | Docs |
alert_dialog |
Confirmation/alert dialog with focus management | Examples |
popover, hover_card, tooltip, dialog, overlay, loading_overlay |
Contextual overlays | Examples |
menu, menubar |
Dropdown and application menus | Examples |
Navigation & Layout
| Component | Description | Documentation |
|---|---|---|
nav_link, tabs, breadcrumbs, pagination, stepper, anchor, burger, table_of_contents |
Navigation primitives | Examples |
navigation_progress |
Page loading progress indicator | Examples |
app_shell, container, stack, group, grid, simple_grid, flex, center, space, divider, affix, scroller, splitter |
Layout building blocks | Examples |
scroll_area |
Scrollable container with custom scrollbars and virtualization | Examples |
floating_window |
Draggable floating panel, resizable via the resize_handle sub-component |
Examples |
Data Display & Feedback
| Component | Description | Documentation |
|---|---|---|
table |
Table component for tabular data display | Examples |
accordion, avatar, badge, card, data_list, empty_state, image, indicator, kbd, paper, spoiler, theme_icon, timeline |
Data display components | Examples |
alert, loader, notification, progress, ring_progress, skeleton |
Feedback components | Examples |
tree, carousel |
Hierarchical and carousel display | Examples |
number_formatter |
Formats numeric input with parser/formatter, returns parsed value | Examples |
Charts
| Component | Description | Documentation |
|---|---|---|
area_chart, bar_chart, line_chart, pie_chart, donut_chart, radar_chart, radial_bar_chart, scatter_chart, composite_chart, bubble_chart, funnel_chart, heatmap, treemap, sankey_chart, sunburst_chart, bullet_chart, sparkline, bars_list |
Recharts-powered charting components | Examples |
chart_brush |
Range selector (brush) for area/bar/line/composite charts | Examples |
Maps & Scheduling
| Component | Description | Documentation |
|---|---|---|
map, MapMarker, MapControls, MapNavigation, MapDirectionsPanel, MapArc, MapGeoJSON, MapRoute, MapClusterLayer |
MapLibre-based map components | Examples |
schedule, resources_schedule, resources_day_view, resources_week_view, resources_month_view, agenda_view |
Calendar/resource scheduling components | Examples / Resources |
Typography & Markdown
| Component | Description | Documentation |
|---|---|---|
text, title, code, mark, highlight, blockquote, list_ |
Typography primitives | Examples |
markdown_preview |
Markdown renderer with Mermaid diagrams and math support | Examples |
Common Props (Inherited by All Inputs)
All input components inherit ~40 common props from MantineInputComponentBase:
# Input.Wrapper props
label = "Field Label"
description = "Helper text"
error = "Validation error"
required = True
with_asterisk = True # Show red asterisk for required fields
# Visual variants
variant = "filled" # "default" | "filled" | "unstyled"
size = "md" # "xs" | "sm" | "md" | "lg" | "xl"
radius = "md" # "xs" | "sm" | "md" | "lg" | "xl"
# State management
value = State.field_value
default_value = "Initial value"
placeholder = "Enter text..."
disabled = False
# Sections (icons, buttons)
left_section = rx.icon("search")
right_section = rx.button("Clear")
left_section_pointer_events = "none" # Click-through
# Mantine style props
w = "100%" # width
maw = "500px" # max-width
m = "md" # margin
p = "sm" # padding
# Event handlers
on_change = State.handle_change
on_focus = State.handle_focus
on_blur = State.handle_blur
📖 Usage Examples
Basic Input with Validation
import reflex as rx
import appkit_mantine as mn
class EmailState(rx.State):
email: str = ""
error: str = ""
def validate_email(self):
if "@" not in self.email:
self.error = "Invalid email format"
else:
self.error = ""
def email_input():
return mn.form.input(
label="Email Address",
description="We'll never share your email",
placeholder="you@example.com",
value=EmailState.email,
on_change=EmailState.set_email,
on_blur=EmailState.validate_email,
error=EmailState.error,
required=True,
type="email",
left_section=rx.icon("mail"),
)
Number Input with Formatting
class PriceState(rx.State):
price: float = 0.0
def price_input():
return mn.number_input(
label="Product Price",
value=PriceState.price,
on_change=PriceState.set_price,
prefix="$",
decimal_scale=2,
fixed_decimal_scale=True,
thousand_separator=",",
min=0,
max=999999.99,
step=0.01,
)
Masked Input (Phone Number)
class PhoneState(rx.State):
phone: str = ""
def handle_phone(self, value: str) -> None:
self.phone = value
def phone_input():
# Use as an UNCONTROLLED component: default_value + on_change (not value)
return mn.masked_input(
label="Phone Number",
mask="+1 (000) 000-0000",
default_value="+1 (555) 123-4567",
on_change=PhoneState.handle_phone,
placeholder="+1 (555) 123-4567",
)
Date Input with Constraints
from datetime import date, timedelta
class BookingState(rx.State):
checkin: str = ""
def date_picker():
today = date.today()
max_date = today + timedelta(days=365)
return mn.date_input(
label="Check-in Date",
value=BookingState.checkin,
on_change=BookingState.set_checkin,
min_date=today.isoformat(),
max_date=max_date.isoformat(),
clear_button_props={"aria_label": "Clear date"},
)
Rich Text Editor
class EditorState(rx.State):
content: str = "<p>Start typing...</p>"
def editor():
return mn.rich_text_editor(
value=EditorState.content,
on_change=EditorState.set_content,
toolbar_config=mn.EditorToolbarConfig(
controls=[
mn.ToolbarControlGroup.FORMATTING,
mn.ToolbarControlGroup.LISTS,
mn.ToolbarControlGroup.LINKS,
]
),
)
Action Icon
def action_icon_example():
return mn.action_icon(
rx.icon("heart"),
variant="filled",
color="red",
size="lg",
on_click=State.like_item,
)
Autocomplete
class SearchState(rx.State):
query: str = ""
def autocomplete_example():
return mn.autocomplete(
label="Search",
placeholder="Type to search...",
data=["Apple", "Banana", "Cherry"],
value=SearchState.query,
on_change=SearchState.set_query,
)
Button
def button_example():
return mn.button(
"Click me",
variant="gradient",
gradient={"from": "blue", "to": "cyan"},
size="lg",
on_click=State.handle_click,
)
Combobox
def combobox_example():
return mn.combobox(
label="Select option",
data=[
{"value": "react", "label": "React"},
{"value": "vue", "label": "Vue"},
],
on_option_submit=State.set_selected,
)
Input
def input_example():
return mn.input(
placeholder="Enter text...",
left_section=rx.icon("search"),
right_section=rx.button("Clear"),
)
JSON Input
class JsonState(rx.State):
data: str = '{"name": "example"}'
def json_input_example():
return mn.json_input(
label="JSON Data",
value=JsonState.data,
on_change=JsonState.set_data,
format_on_blur=True,
)
Nav Link
def nav_link_example():
return mn.nav_link(
label="Dashboard",
left_section=rx.icon("home"),
active=True,
on_click=State.navigate_to_dashboard,
)
Number Formatter
class PriceState(rx.State):
amount: float = 1234.56
def number_formatter_example():
return mn.number_formatter(
value=PriceState.amount,
prefix="$",
thousand_separator=",",
decimal_scale=2,
)
Select
class SelectState(rx.State):
choice: str = ""
def select_example():
return mn.select(
label="Choose one",
data=["Option 1", "Option 2", "Option 3"],
value=SelectState.choice,
on_change=SelectState.set_choice,
)
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
Metadata
Release files for appkit-mantine 1.15.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| appkit_mantine-1.15.0.tar.gz | 250.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| appkit_mantine-1.15.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 558.3 kB
Release files / appkit_mantine-1.15.0.tar.gz
| Download URL | appkit_mantine-1.15.0.tar.gz |
|---|---|
| Size | 250.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
90f7c5916b82035df271a1b225be8816b370f4adfcaeed34c86e5b48e8c5ff50
|
|
BLAKE2b-256 checksum How to use checksums |
080577dd2d46dd8be54eb6e59bce1f8b0adaa43e7af7159f6867eba204450ea3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / appkit_mantine-1.15.0-py3-none-any.whl
| Download URL | appkit_mantine-1.15.0-py3-none-any.whl |
|---|---|
| Size | 308.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3e6a0d298876c8e80bda890ea7501f8e0de828e0f6cbd56a55c1e6d2e4d9c1ec
|
|
BLAKE2b-256 checksum How to use checksums |
e523d6b1692f84ecb0a4a0ac63e01817d785906a6e9499430809cdb0b0b31f6c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|