Python + React UI Framework for Building Reactive Web Applications
Refast is a modern, high-performance web framework that enables building reactive single-page applications (SPAs) entirely in Python. It uses FastAPI for the backend server and compiles a high-fidelity React frontend powered by shadcn/ui and Tailwind CSS. Communication between Python and React happens seamlessly in real-time over a persistent WebSocket connection.
📖 Documentation: For full component guides and API references, visit refast.fastapicloud.com.
Get up and running with a simple reactive application in a few minutes.
Install Refast and its production dependencies using pip or uv:
pip install refastCreate a file named app.py and add the following code:
import uvicorn
from fastapi import FastAPI
from refast import RefastApp, Context
from refast import components as rc
# Initialize the Refast application
ui = RefastApp(title="Refast Quick Start")
# Define an asynchronous callback for interactivity
async def handle_click(ctx: Context):
# Targeted text update using the component's ID (highly efficient!)
await ctx.update_text("status-text", "Refast is reactive! 🚀")
# Trigger a beautiful toast notification
await ctx.show_toast("Message updated!", variant="success")
# Define a synchronous page layout handler
@ui.page("/")
def home(ctx: Context):
return rc.Container(
children=[
rc.Column(
children=[
rc.Heading("Hello, Refast!", level=1),
rc.Text(
"Click the button below to trigger a reactive update.",
id="status-text",
class_name="text-muted-foreground text-center"
),
rc.Button(
"Click Me",
on_click=ctx.callback(handle_click)
),
],
gap=4,
align="center",
)
],
class_name="p-8 max-w-md mx-auto mt-20 border rounded-lg shadow-sm bg-card"
)
# Mount the Refast router to a FastAPI app
app = FastAPI()
app.include_router(ui.router)
if __name__ == "__main__":
# Start the local development server
uvicorn.run(app, host="127.0.0.1", port=8000)Run the application:
python app.pyNow open http://127.0.0.1:8000 in your browser!
Traditional web development requires managing separate backend APIs and frontend codebases, dealing with state synchronization, and writing JavaScript. Refast removes these friction points:
- Write Python Only: Define your user interface, styling, layout, database interactions, and state mutations purely in Python.
- Instant React Reactivity: Components react instantly to server-side state updates over WebSockets without full-page reloads.
- Beautiful Out-of-the-Box Components: Native integration with pre-styled, accessible
shadcn/uicomponents (Buttons, Inputs, DataTables, Dialogs, Tabs, Calendars, Tooltips, etc.). - Fine-Grained DOM Control: Low-latency Context API updates (e.g., append list items, change element classes, swap subtrees, or update text fields directly) to keep interfaces fast and snappy.
- Easy Styling: Apply styling using Tailwind utility classes (
class_name="...") or inline styles (style={...}) directly on components. - Extensible: Highly extensible. Easily build and register custom components or write extensions to integrate with third-party React/JavaScript libraries.
- FastAPI Native: Refast is packaged as a FastAPI router, meaning you can easily mount it into any new or existing FastAPI application.
Refast divides application code into two distinct types of functions:
- Page Handlers (Sync
def): Run on initial page load or when a section requires a fresh layout. They build and return a component tree. - Callback Handlers (Async
async def): Run when a user interacts with the UI (e.g., clicking a button, typing in a field, selecting options). Callbacks mutate state, trigger backend business logic, and send back targeted updates to the browser.
While you can refresh an entire page via await ctx.refresh(), Refast encourages high-performance targeted updates to keep latency low. The Context object (ctx) provides several methods for this:
| Method | Scope / Cost | Recommended Use Case |
|---|---|---|
await ctx.update_text(id, text) |
Single string update | Modifying status labels, headers, or counter values. |
await ctx.update_props(id, props) |
Prop updates only | Enabling/disabling inputs, changing colors, or toggling state. |
await ctx.replace(id, component) |
Subtree replacement | Swapping cards, forms, or content sections. |
await ctx.append(id, component) |
Add child element | Adding a new chat message, a log entry, or a list item. |
await ctx.prepend(id, component) |
Prepend child element | Adding a message or item at the top of a container. |
await ctx.remove(id) |
Delete element | Removing specific list items or alerts from the screen. |
await ctx.show_toast(msg) |
Toast notification | Alerting users about action outcomes (success, error). |
await ctx.refresh(target_id=...) |
Target subtree re-render | Re-running page logic for a specific container. |
Refast supports several types of callbacks to handle frontend events and bridge the gap between Python and JavaScript:
These are used to bind event handlers (like on_click, on_change) to components in your page layouts:
- Python Callbacks (
ctx.callback): Invokes a Python function on the server via WebSocket.rc.Button("Save", on_click=ctx.callback(handle_save))
- Client-Side JS Callbacks (
ctx.js): Executes inline JavaScript code directly on the client side without a server roundtrip.rc.Button("Alert", on_click=ctx.js("alert('Hello!')"))
- Bound Component Method Callbacks (
ctx.bound_js): Calls a specific method on a React component on the frontend.rc.Button("Clear Canvas", on_click=ctx.bound_js("canvas-id", "clearCanvas"))
You can execute JavaScript or trigger component methods dynamically from within other Python callbacks using the following async Context methods:
- Execute JavaScript (
ctx.call_js): Triggers immediate client-side JS execution from within a Python callback.async def handle_save(ctx: Context): # ... perform server-side database save ... await ctx.call_js("confetti({ particleCount: 100 })")
- Call Bound Component Methods (
ctx.call_bound_js): Commands a component to perform a built-in method from within a Python callback.async def reset_board(ctx: Context): # ... reset server-side board state ... await ctx.call_bound_js("game-board", "resetState")
Refast provides multiple ways to manage application state:
Lives for the duration of the WebSocket connection. If the user refreshes the browser page, it resets.
# Set value
ctx.state["count"] = ctx.state.get("count", 0) + 1
# Get value
count = ctx.state["count"]Persists data on the client side using browser storage.
# Persistent localStorage (survives browser restarts)
ctx.store.local.set("user_theme", "dark")
# Session storage (survives tab lifetime)
ctx.store.session.set("wizard_step", 2)To set up a local development environment for Refast:
# Clone the repository
git clone https://github.com/idling-mind/refast.git
cd refast
# Install in editable mode with development dependencies
pip install -e ".[dev]"
# Run tests
pytest tests/
# Run linting and code quality checks
ruff check src/Refast is released under the MIT License.