Skip to content

Commit 39fb9fd

Browse files
Improve assets documentation
Co-Authored-By: Alek Petuskey <[email protected]>
1 parent c2bbe47 commit 39fb9fd

File tree

3 files changed

+303
-49
lines changed

3 files changed

+303
-49
lines changed

docs/assets/overview.md

Lines changed: 101 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import reflex as rx
44

55
# Assets
66

7-
Static files such as images and stylesheets can be placed in `assets/` folder of the project. These files can be referenced within your app.
7+
Static files such as images, stylesheets, fonts, and other resources can be placed in the `assets/` folder of your Reflex project. These files are automatically made available to your application during both development and production.
88

99
```md alert
1010
# Assets are copied during the build process.
@@ -13,9 +13,39 @@ Any files placed within the `assets/` folder at runtime will not be available to
1313
when running in production mode. The `assets/` folder should only be used for static files.
1414
```
1515

16+
## Types of Assets
17+
18+
Reflex supports various types of static assets:
19+
20+
- **Images**: PNG, JPG, GIF, SVG, WebP, etc.
21+
- **Stylesheets**: CSS files
22+
- **Fonts**: TTF, OTF, WOFF, WOFF2
23+
- **Scripts**: JavaScript files
24+
- **Data files**: JSON, CSV, etc.
25+
- **Media**: Audio, video files
26+
- **Documents**: PDF, etc.
27+
28+
## Asset Directory Structure
29+
30+
The `assets/` directory is located at the root of your Reflex project. You can organize your assets in subdirectories for better management:
31+
32+
```bash
33+
assets/
34+
├── images/
35+
│ ├── logo.png
36+
│ └── background.jpg
37+
├── css/
38+
│ └── custom.css
39+
├── fonts/
40+
│ └── custom-font.ttf
41+
├── js/
42+
│ └── script.js
43+
└── favicon.ico
44+
```
45+
1646
## Referencing Assets
1747

18-
To reference an image in the `assets/` simply pass the relative path as a prop.
48+
To reference an asset in your Reflex app, use the path relative to the `assets/` directory, prefixed with a forward slash `/`.
1949

2050
For example, you can store your logo in your assets folder:
2151

@@ -34,8 +64,76 @@ rx.image(src="/Reflex.svg", width="5em")
3464
# Always prefix the asset path with a forward slash `/` to reference the asset from the root of the project, or it may not display correctly on non-root pages.
3565
```
3666

67+
## Using Assets in Different Components
68+
69+
Assets can be used in various Reflex components:
70+
71+
### Images
72+
73+
```python
74+
rx.image(src="/images/logo.png", width="100px")
75+
```
76+
77+
### CSS Stylesheets
78+
79+
```python
80+
rx.link(rel="stylesheet", href="/css/custom.css")
81+
```
82+
83+
### JavaScript Files
84+
85+
```python
86+
rx.script(src="/js/script.js")
87+
```
88+
89+
### Background Images in Style Props
90+
91+
```python
92+
rx.box(
93+
width="100%",
94+
height="200px",
95+
background_image="url('/images/background.jpg')",
96+
background_size="cover",
97+
)
98+
```
99+
100+
## Shared Assets
101+
102+
For library developers, Reflex provides a way to share assets from your library with applications that use your library. This is done using the `rx.asset()` function:
103+
104+
```python
105+
rx.image(src=rx.asset(path="my_image.png", shared=True))
106+
```
107+
108+
When `shared=True`, the asset is expected to be located next to the Python file that references it, not in the app's `assets/` directory. Reflex will automatically create a symlink to make the asset available to the app.
109+
110+
You can also specify a subfolder for shared assets:
111+
112+
```python
113+
rx.image(src=rx.asset(path="my_image.png", shared=True, subfolder="images"))
114+
```
115+
37116
## Favicon
38117

39118
The favicon is the small icon that appears in the browser tab.
40119

41-
You can add a `favicon.ico` file to the `assets/` folder to change the favicon.
120+
You can add a `favicon.ico` file to the `assets/` folder to change the favicon. Reflex will automatically detect and use this file.
121+
122+
For more modern favicon formats, you can also include:
123+
124+
```html
125+
<!-- In your head component -->
126+
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
127+
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
128+
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
129+
```
130+
131+
## Asset Optimization
132+
133+
When building your app for production with `reflex deploy` or `reflex export`, Reflex will automatically optimize your assets:
134+
135+
- Images may be compressed
136+
- CSS and JavaScript files may be minified
137+
- Assets are given unique filenames for cache busting
138+
139+
This optimization helps improve the performance of your application in production.

docs/assets/upload_and_download_files.md

Lines changed: 189 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,57 +6,80 @@ from pcweb.pages.docs import api_reference
66

77
# Files
88

9-
In addition to any assets you ship with your app, many web app will often need to receive or send files, whether you want to share media, allow user to import their data, or export some backend data.
9+
In addition to static assets that ship with your app, many web applications need to handle dynamic file operations such as:
1010

11-
In this section, we will cover all you need to know for manipulating files in Reflex.
11+
- Allowing users to download files from your server
12+
- Enabling users to upload files to your server
13+
- Processing uploaded files on the backend
14+
- Generating files dynamically for download
15+
16+
This section covers everything you need to know about file handling in Reflex.
1217

1318
## Download
1419

15-
If you want to let the users of your app download files from your server to their computer, Reflex offer you two way.
20+
Reflex offers multiple ways to let users download files from your server to their computer.
1621

17-
### With a regular link
22+
### With a Regular Link
1823

19-
For some basic usage, simply providing the path to your resource in a `rx.link` will work, and clicking the link will download or display the resource.
24+
For basic usage, simply providing the path to your resource in an `rx.link` component will work. Clicking the link will download or display the resource depending on the file type and browser settings.
2025

2126
```python demo
22-
rx.link("Download", href="/reflex_banner.png")
27+
rx.link("Download Image", href="/reflex_banner.png")
2328
```
2429

25-
### With `rx.download` event
30+
This approach works well for:
31+
- Static files in your assets directory
32+
- Files that can be displayed in the browser (images, PDFs, etc.)
33+
- Simple download scenarios
34+
35+
### With `rx.download` Event
2636

27-
Using the `rx.download` event will always prompt the browser to download the file, even if it could be displayed in the browser.
37+
For more control over the download process, use the `rx.download` event. This approach:
38+
- Always prompts the browser to download the file (even if it could be displayed)
39+
- Can be triggered from any UI event or backend event handler
40+
- Allows renaming the downloaded file
41+
- Supports dynamically generated content
2842

29-
The `rx.download` event also allows the download to be triggered from another backend event handler.
43+
#### Basic Download
3044

3145
```python demo
3246
rx.button(
33-
"Download",
47+
"Download Image",
3448
on_click=rx.download(url="/reflex_banner.png"),
3549
)
3650
```
3751

38-
`rx.download` lets you specify a name for the file that will be downloaded, if you want it to be different from the name on the server side.
52+
#### Renaming Downloaded Files
53+
54+
You can specify a different filename for the downloaded file:
3955

4056
```python demo
4157
rx.button(
4258
"Download and Rename",
4359
on_click=rx.download(
4460
url="/reflex_banner.png",
45-
filename="different_name_logo.png"
61+
filename="reflex_logo.png"
4662
),
4763
)
4864
```
4965

50-
If the data to download is not already available at a known URL, pass the `data` directly to the `rx.download` event from the backend.
66+
#### Dynamically Generated Downloads
67+
68+
If the data to download is not already available at a known URL, you can pass the `data` directly to the `rx.download` event from the backend:
5169

5270
```python demo exec
5371
import random
5472

5573
class DownloadState(rx.State):
5674
@rx.event
5775
def download_random_data(self):
76+
"""Generate and download random data as a CSV file."""
77+
# Generate random data
78+
data = ",".join([str(random.randint(0, 100)) for _ in range(10)])
79+
80+
# Return a download event with the data
5881
return rx.download(
59-
data=",".join([str(random.randint(0, 100)) for _ in range(10)]),
82+
data=data,
6083
filename="random_numbers.csv"
6184
)
6285

@@ -67,24 +90,167 @@ def download_random_data_button():
6790
)
6891
```
6992

70-
The `data` arg accepts `str` or `bytes` data, a `data:` URI, `PIL.Image`, or any state Var. If the Var is not already a string, it will be converted to a string using `JSON.stringify`. This allows complex state structures to be offered as JSON downloads.
93+
#### Supported Data Types
94+
95+
The `data` parameter of `rx.download` accepts various types:
7196

72-
Reference page for `rx.download` [here]({api_reference.special_events.path}#rx.download).
97+
- `str`: Text data (will be encoded as UTF-8)
98+
- `bytes`: Binary data
99+
- `data:` URI: For inline data
100+
- `PIL.Image`: Image objects from the Pillow library
101+
- Any state `Var`: Will be converted to JSON if not already a string
102+
103+
This flexibility allows you to offer complex state structures as JSON downloads:
104+
105+
```python
106+
@rx.event
107+
def download_user_data(self):
108+
"""Download the user's data as a JSON file."""
109+
return rx.download(
110+
data=self.user_data, # This could be a dict or any JSON-serializable object
111+
filename="user_data.json"
112+
)
113+
```
114+
115+
For more details on `rx.download`, see the [reference page]({api_reference.special_events.path}#rx.download).
73116

74117
## Upload
75118

76-
Uploading files to your server let your users interact with your app in a different way than just filling forms to provide data.
119+
File uploads are essential for many web applications. Reflex provides the `rx.upload` component to handle file uploads with features like:
77120

78-
The component `rx.upload` let your users upload files on the server.
121+
- Drag-and-drop support
122+
- Multiple file selection
123+
- File type filtering
124+
- Upload progress tracking
125+
- Cancellation support
79126

80-
Here is a basic example of how it is used:
127+
### Basic Upload Example
128+
129+
Here's a simple example of how to use the upload component:
81130

82131
```python
132+
class UploadState(rx.State):
133+
"""State for handling file uploads."""
134+
135+
# Store the uploaded filenames
136+
files: list[str] = []
137+
138+
@rx.event
139+
async def handle_upload(self, files: list[rx.UploadFile]):
140+
"""Process uploaded files.
141+
142+
Args:
143+
files: List of uploaded files from the frontend.
144+
"""
145+
for file in files:
146+
# Read the file data
147+
upload_data = await file.read()
148+
149+
# Define the output path
150+
outfile = rx.get_upload_dir() / file.filename
151+
152+
# Save the file
153+
with outfile.open("wb") as file_object:
154+
file_object.write(upload_data)
155+
156+
# Update the state with the filename
157+
self.files.append(file.filename)
158+
83159
def index():
84-
return rx.fragment(
85-
rx.upload(rx.text("Upload files"), rx.icon(tag="upload")),
86-
rx.button(on_submit=State.<your_upload_handler>)
160+
"""The main view with upload functionality."""
161+
return rx.vstack(
162+
# Upload component
163+
rx.upload(
164+
rx.vstack(
165+
rx.button("Select Files", color="primary"),
166+
rx.text("or drag and drop files here"),
167+
),
168+
id="file_upload",
169+
border="1px dashed #ccc",
170+
padding="2em",
171+
),
172+
173+
# Display selected files
174+
rx.hstack(rx.foreach(rx.selected_files("file_upload"), rx.text)),
175+
176+
# Upload button
177+
rx.button(
178+
"Upload Files",
179+
on_click=UploadState.handle_upload(rx.upload_files(upload_id="file_upload")),
180+
),
181+
182+
# Clear selection button
183+
rx.button(
184+
"Clear Selection",
185+
on_click=rx.clear_selected_files("file_upload"),
186+
),
187+
188+
# Display uploaded files
189+
rx.vstack(
190+
rx.heading("Uploaded Files"),
191+
rx.foreach(
192+
UploadState.files,
193+
lambda filename: rx.link(
194+
filename,
195+
href=rx.get_upload_url(filename),
196+
target="_blank",
197+
),
198+
),
199+
),
200+
spacing="4",
201+
padding="2em",
87202
)
88203
```
89204

90-
For detailed information, see the reference page of the component [here]({library.forms.upload.path}).
205+
### Upload Process Flow
206+
207+
1. User selects files via the `rx.upload` component (by clicking or drag-and-drop)
208+
2. Selected files appear in the UI using `rx.selected_files("upload_id")`
209+
3. User clicks an upload button that triggers an event handler with `rx.upload_files(upload_id="upload_id")`
210+
4. The event handler receives the files as `list[rx.UploadFile]` objects
211+
5. The handler processes the files (saving, analyzing, etc.)
212+
6. The UI updates to reflect the uploaded files
213+
214+
### File Storage and Access
215+
216+
Reflex provides helper functions to manage uploaded files:
217+
218+
#### `rx.get_upload_dir()`
219+
220+
Returns the directory where uploaded files should be saved. By default, this is `./uploaded_files` in your project root, but it can be configured with the `REFLEX_UPLOADED_FILES_DIR` environment variable.
221+
222+
```python
223+
# Save an uploaded file
224+
outfile = rx.get_upload_dir() / file.filename
225+
with outfile.open("wb") as f:
226+
f.write(file_data)
227+
```
228+
229+
#### `rx.get_upload_url(filename)`
230+
231+
Returns the URL to access an uploaded file. This URL is automatically mounted by Reflex at `/_upload/`.
232+
233+
```python
234+
# Display an uploaded image
235+
rx.image(src=rx.get_upload_url("my_image.jpg"))
236+
237+
# Create a link to an uploaded file
238+
rx.link("Download PDF", href=rx.get_upload_url("document.pdf"))
239+
```
240+
241+
```md alert info
242+
# File Persistence Warning
243+
244+
When using the Reflex hosting service, the uploaded files directory is not persistent and will be cleared on every deployment. For persistent storage of uploaded files in production, it's recommended to use an external service such as AWS S3, Google Cloud Storage, or similar cloud storage solutions.
245+
```
246+
247+
### Advanced Upload Features
248+
249+
For more advanced upload scenarios, see the [Upload component reference]({library.forms.upload.path}) which covers:
250+
251+
- Multiple file uploads
252+
- Single file uploads
253+
- File type restrictions
254+
- Upload progress tracking
255+
- Upload cancellation
256+
- Custom styling

0 commit comments

Comments
 (0)