diff --git a/examples/custom_vue_component/README.md b/examples/custom_vue_component/README.md
new file mode 100644
index 000000000..820a26157
--- /dev/null
+++ b/examples/custom_vue_component/README.md
@@ -0,0 +1,21 @@
+# Custom Vue Component
+
+This example demonstrates how to create and use custom Vue components in NiceGUI.
+One component is implemented using JavaScript, the other using Vue's Single-File Component (SFC) syntax.
+
+## Counter Component (counter.js)
+
+The `Counter` component is a simple counter that increments a value.
+On change, it emits an event with the new value.
+A reset method allows to reset the counter to 0.
+
+The JavaScript code in `counter.js` defines the front-end logic of the component using JavaScript.
+
+## OnOff Component (on_off.vue)
+
+The `OnOff` component is a simple toggle that switches between on and off.
+On change, it emits an event with the new value.
+A reset method is also provided to reset the toggle to off.
+
+The Single-File Component in `on_off.vue` defines the front-end logic of the component using Vue 2.
+In contrast to the JavaScript code in `counter.js`, it splits the template, script, and style into separate sections.
diff --git a/examples/custom_vue_component/counter.js b/examples/custom_vue_component/counter.js
index 16b40fd16..f005a9920 100644
--- a/examples/custom_vue_component/counter.js
+++ b/examples/custom_vue_component/counter.js
@@ -1,9 +1,13 @@
// NOTE: Make sure to reload the browser with cache disabled after making changes to this file.
export default {
template: `
- `,
+
+ `,
+ props: {
+ title: String,
+ },
data() {
return {
value: 0,
@@ -18,7 +22,4 @@ export default {
this.value = 0;
},
},
- props: {
- title: String,
- },
};
diff --git a/examples/custom_vue_component/main.py b/examples/custom_vue_component/main.py
index bd373eecf..f6b104629 100755
--- a/examples/custom_vue_component/main.py
+++ b/examples/custom_vue_component/main.py
@@ -1,17 +1,16 @@
#!/usr/bin/env python3
from counter import Counter
+from on_off import OnOff
from nicegui import ui
-ui.markdown('''
-#### Try the new click counter!
+with ui.row(align_items='center'):
+ counter = Counter('Count', on_change=lambda e: ui.notify(f'The value changed to {e.args}.'))
+ ui.button('Reset', on_click=counter.reset).props('outline')
-Click to increment its value.
-''')
-with ui.card():
- counter = Counter('Clicks', on_change=lambda e: ui.notify(f'The value changed to {e.args}.'))
+with ui.row(align_items='center'):
+ on_off = OnOff('State', on_change=lambda e: ui.notify(f'The value changed to {e.args}.'))
+ ui.button('Reset', on_click=on_off.reset).props('outline')
-ui.button('Reset', on_click=counter.reset).props('small outline')
-
-ui.run()
+ui.run(uvicorn_reload_includes='*.py,*.js,*.vue')
diff --git a/examples/custom_vue_component/on_off.py b/examples/custom_vue_component/on_off.py
new file mode 100644
index 000000000..90328b8a8
--- /dev/null
+++ b/examples/custom_vue_component/on_off.py
@@ -0,0 +1,14 @@
+from typing import Callable, Optional
+
+from nicegui.element import Element
+
+
+class OnOff(Element, component='on_off.vue'):
+
+ def __init__(self, title: str, *, on_change: Optional[Callable] = None) -> None:
+ super().__init__()
+ self._props['title'] = title
+ self.on('change', on_change)
+
+ def reset(self) -> None:
+ self.run_method('reset')
diff --git a/examples/custom_vue_component/on_off.vue b/examples/custom_vue_component/on_off.vue
new file mode 100644
index 000000000..f5d91b1d5
--- /dev/null
+++ b/examples/custom_vue_component/on_off.vue
@@ -0,0 +1,41 @@
+
+