diff --git a/src/personal_mcp/docs/skills/nicegui/references/component-mechanics.md b/src/personal_mcp/docs/skills/nicegui/references/component-mechanics.md
index 99db506..9d45f34 100644
--- a/src/personal_mcp/docs/skills/nicegui/references/component-mechanics.md
+++ b/src/personal_mcp/docs/skills/nicegui/references/component-mechanics.md
@@ -1,6 +1,190 @@
# NiceGUI Component Mechanics
-Use this reference to understand how customization crosses the NiceGUI Python wrapper, Quasar component, Vue runtime, and browser DOM. It owns constructor behavior, prop translation, events, bindings, slots, frontend methods, detached content, and component-specific caveats. For themes, utility classes, CSS properties, responsive page composition, and other cosmetic work, load [visual styling and CSS](./styling-and-customization.md).
+NiceGUI components are Python objects that describe browser UI elements. A component constructor creates an element, constructor arguments configure its common behavior, and methods on the returned object expose styling, events, bindings, slots, and client-side capabilities.
+
+This reference begins with those everyday component APIs, then describes the NiceGUI, Quasar, Vue, and browser layers beneath them. Themes, responsive composition, and broader visual design are covered separately in [visual styling and CSS](./styling-and-customization.md).
+
+## Basic Components
+
+Components are created from the `ui` namespace. Layout components are context managers, so nested Python blocks describe the element hierarchy:
+
+```python
+from nicegui import ui
+
+with ui.column().classes("gap-3"):
+ name = ui.input("Name", placeholder="Ada")
+ role = ui.select(
+ options={"admin": "Administrator", "reader": "Reader"},
+ value="reader",
+ label="Role",
+ ).props("outlined dense")
+ ui.button("Save", on_click=lambda: ui.notify(f"Saved {name.value}"))
+```
+
+The [NiceGUI component documentation](https://nicegui.io/documentation) is the index of available `ui.*` constructors. Each component page documents its Python parameters, values, callbacks, methods, and examples. The implementation for each wrapper is available in the [NiceGUI element source tree](https://github.com/zauberzeug/nicegui/tree/main/nicegui/elements).
+
+## Common Component Mechanics
+
+Most NiceGUI elements inherit a common set of mechanics from `Element`; individual wrappers add component-specific properties and methods.
+
+| Surface | What it represents | Source of supported values |
+| --- | --- | --- |
+| Constructor arguments | NiceGUI's typed, Python-facing API for initial content, values, callbacks, validation, and common behavior | the component's page in the [NiceGUI component documentation](https://nicegui.io/documentation) and its wrapper in the [NiceGUI element source tree](https://github.com/zauberzeug/nicegui/tree/main/nicegui/elements) |
+| Properties such as `.value` and `.options` | Python-side component state maintained by a particular wrapper | the component documentation and wrapper source; these properties are not universal `Element` APIs |
+| Wrapper methods such as `set_options()` | NiceGUI state transitions that normalize Python data and schedule a client update | the component documentation and wrapper source |
+| `.props(...)` | Quasar component props, Vue bindings, or HTML attributes serialized onto the frontend element | the API section of the wrapped component in the [Quasar component documentation](https://quasar.dev/vue-components); [NiceGUI element customization](https://nicegui.io/documentation/element) defines the bridge syntax |
+| `.classes(...)` | CSS class names attached to the element | [Tailwind's utility documentation](https://tailwindcss.com/docs) for Tailwind classes; Quasar's [breakpoint](https://quasar.dev/style/breakpoints), [spacing](https://quasar.dev/style/spacing), [visibility](https://quasar.dev/style/visibility), and [helper-class](https://quasar.dev/style/other-helper-classes) references for Quasar classes; or the application's own stylesheets for custom classes |
+| `.style(...)` | Inline CSS declarations attached to the element | the [MDN CSS reference](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference) |
+| Constructor callbacks and `.on(...)` | NiceGUI callbacks and forwarded browser or Quasar events | the component's NiceGUI page first, then the Events section of its Quasar API; [NiceGUI generic events](https://nicegui.io/documentation/generic_events) documents `.on(...)` |
+| `on_*` methods | Named event conveniences implemented by a specific NiceGUI wrapper, such as `on_value_change` | the component documentation and wrapper source; there is no universal list that applies to every component |
+| `bind_*` methods | synchronization between element properties and Python model properties | [NiceGUI binding documentation](https://nicegui.io/documentation/section_binding_properties) and the wrapper's documented bindable properties |
+| `add_slot(...)` | content inserted into a Quasar or Vue named slot | the Slots and Scoped Slots sections of the wrapped component's Quasar API |
+| `run_method(...)` | invocation of a public method on the client component | the Methods section of the wrapped component's Quasar API |
+
+### Options And Values
+
+`options` is component state rather than a universal styling mechanism. Components such as `ui.select`, `ui.radio`, `ui.toggle`, and `ui.table` define their own accepted option shapes and value semantics. For example, NiceGUI's [`ui.select` documentation](https://nicegui.io/documentation/select) describes list and dictionary options, while the [`Select` wrapper source](https://github.com/zauberzeug/nicegui/blob/main/nicegui/elements/select.py) shows how those Python values are normalized for Quasar.
+
+Reading `element.options` accesses the wrapper's current Python-side options. Assigning or mutating options only changes browser state when the wrapper detects or sends an update. Component helpers such as `set_options()` encode that synchronization behavior and therefore belong to the wrapper's API rather than to Quasar's raw `options` prop.
+
+### Props
+
+`.props()` writes props onto the frontend component:
+
+```python
+ui.button("Archive").props("outline color=negative")
+ui.select(["A", "B"]).props("dense options-dense")
+```
+
+For NiceGUI elements backed by Quasar, supported names and values come from the wrapped Quasar component's API. For example, the full [`QSelect` API](https://quasar.dev/vue-components/select#qselect-api) lists `dense`, `options-dense`, `popup-content-class`, events, slots, and methods. NiceGUI may already expose some of those features as typed constructor arguments or wrapper methods; the NiceGUI component page and source describe that higher-level behavior.
+
+#### Property-String Format
+
+NiceGUI's `.props()` string is parsed on the Python side by the tagged [`Props.parse()` implementation](https://github.com/zauberzeug/nicegui/blob/v3.16.0/nicegui/props.py). It accepts whitespace-delimited tokens in these forms:
+
+| Form | Python-side result | Frontend meaning |
+| --- | --- | --- |
+| `dense` | `{"dense": True}` | a true boolean prop |
+| `label=Chair` | `{"label": "Chair"}` | a static string prop |
+| `offset=[8, 8]` | `{"offset": [8, 8]}` | a Python literal serialized as a value |
+| `:label=someExpression` | `{":label": "someExpression"}` | a JavaScript expression evaluated in the browser |
+
+Quoted strings and bracketed or braced literals are parsed with Python's `ast.literal_eval`; unquoted values remain strings. Quote an expression when it contains whitespace or characters outside NiceGUI's unquoted-value grammar, or assign it through `element.props[":name"]` to avoid the string parser. Regular HTML attributes can pass through the same mechanism where the rendered element supports them. The [NiceGUI element documentation](https://nicegui.io/documentation/element) defines the public bridge syntax.
+
+#### Dynamic Props And Vue Bindings
+
+The leading colon borrows Vue's [`v-bind` shorthand](https://vuejs.org/api/built-in-directives.html#v-bind), but NiceGUI elements are created with Vue's `h()` render function rather than compiled from a template. NiceGUI's tagged [`renderRecursively()` implementation](https://github.com/zauberzeug/nicegui/blob/v3.16.0/nicegui/static/nicegui.js) removes the colon, evaluates the value as JavaScript, and passes the result in the vnode's props object. For example:
+
+```python
+ui.badge().props(':color="window.innerWidth < 600 ? \'primary\' : \'grey\'"')
+```
+
+corresponds conceptually to this Vue template:
+
+```vue
+
+```
+
+The right-hand side is JavaScript, not Python. It may read browser globals, call functions, or construct arrays and objects, provided the receiving HTML element or Vue component accepts the resulting property. Inside a scoped slot, NiceGUI additionally makes that slot's current scope object available under the name `props`; outside a scoped slot, that name has no slot object to reference.
+
+There is one important render-function distinction. Vue template syntax allows argument-less `v-bind="object"` to spread every key in an object. A literal `.props("v-bind=someObject")` token is not compiled as a directive by NiceGUI's render-function path and does not spread the object. Use a raw `add_slot(..., template=...)` Vue template when a slot contract requires whole-object binding, or bind the documented fields individually. Vue's [render-function reference](https://vuejs.org/guide/extras/render-function.html#creating-vnodes) defines the equivalent programmatic form as passing or spreading those keys in the object supplied to `h()`.
+
+### Classes And Styles
+
+`.classes()` adds class names to the rendered element:
+
+```python
+ui.label("Account").classes("text-lg font-semibold text-slate-800")
+ui.row().classes("w-full items-center gap-4")
+```
+
+NiceGUI includes Tailwind-compatible utility styling, so names such as `flex`, `gap-4`, `w-full`, and `text-slate-800` are defined by Tailwind. The complete categorized list is the [Tailwind CSS documentation](https://tailwindcss.com/docs); its [utility-class guide](https://tailwindcss.com/docs/styling-with-utility-classes) explains variants, responsive prefixes, and arbitrary values. NiceGUI can alternatively run with a selected UnoCSS preset, whose compatibility limits are documented under [NiceGUI's UnoCSS engine](https://nicegui.io/documentation/section_styling_appearance#unocss_engine).
+
+Quasar publishes its classes by category rather than through a single style index. The [breakpoint reference](https://quasar.dev/style/breakpoints) defines viewport thresholds, the [spacing reference](https://quasar.dev/style/spacing) lists the `q-p*` and `q-m*` permutations, the [visibility reference](https://quasar.dev/style/visibility) covers responsive and platform visibility, and the [other helper classes reference](https://quasar.dev/style/other-helper-classes) covers pointer, scrolling, sizing, rotation, and border helpers. Application-defined class names are supported when their CSS is loaded with `ui.add_css`, static assets, or page head content. `.style()` accepts CSS declarations directly, separated by semicolons.
+
+### Events And `on_*` Methods
+
+Callbacks supplied by a constructor are NiceGUI's documented event surface:
+
+```python
+ui.input("Search", on_change=lambda event: print(event.value))
+ui.button("Refresh", on_click=lambda: print("refresh"))
+```
+
+Some wrappers also expose named registration methods such as `on_value_change`. Their availability and event argument type are component-specific and are documented on the NiceGUI component page or in its wrapper source.
+
+`.on()` is the generic event bridge for events without a dedicated Python convenience API:
+
+```python
+field = ui.select(["A", "B"])
+field.on("popup-show", lambda: print("opened"))
+```
+
+For Quasar-backed elements, the component API's Events section is the authoritative list of emitted event names and payloads. Native browser events are documented in the [MDN event reference](https://developer.mozilla.org/en-US/docs/Web/Events). NiceGUI's [generic event documentation](https://nicegui.io/documentation/generic_events) defines the public `.on()` API.
+
+#### Mapping Quasar Event Names
+
+Quasar documents each component event under its **Events** API entry. Use the documented kebab-case name with `.on()`. NiceGUI's tagged [`event_type_to_camel_case()` helper](https://github.com/zauberzeug/nicegui/blob/v3.16.0/nicegui/helpers/strings.py) converts the event name before the first modifier dot to the camelCase form emitted by the component; its frontend renderer then creates Vue's `onXxx` listener prop. These forms therefore map to the same event path:
+
+| Quasar API name | NiceGUI registration | Vue runtime listener |
+| --- | --- | --- |
+| `popup-show` | `.on("popup-show", ...)` | `onPopupShow` |
+| `input-value` | `.on("input-value", ...)` | `onInputValue` |
+| `update:model-value` | `.on("update:model-value", ...)` | `onUpdate:modelValue` |
+
+Vue component events are notifications emitted by the direct component; unlike DOM events, they do not bubble through component ancestors. Prefer a NiceGUI constructor callback, binding, or named wrapper method when one already owns the same behavior. In particular, use `on_change` or a value binding instead of registering another `update:model-value` listener unless the lower-level model event is specifically required.
+
+#### Reading Event Payloads
+
+The Quasar event's documented `params` define the positional arguments received by the listener. NiceGUI serializes those arguments and exposes them as `GenericEventArguments.args` in Python. If exactly one argument is emitted, NiceGUI presents that value directly; multiple emitted arguments remain a list in their documented order.
+
+For example, the version-matched [`QSelect` event API](https://github.com/quasarframework/quasar/blob/quasar-v2.18.5/ui/src/components/select/QSelect.json) defines `add` as one details object containing `index` and `value`:
+
+```python
+def handle_add(event) -> None:
+ print(event.args["index"], event.args["value"])
+
+item_select.on("add", handle_add, args=["index", "value"])
+```
+
+The `args` parameter controls transport, not Quasar's event signature:
+
+| `args` value | Data sent to Python |
+| --- | --- |
+| `None` | all JSON-serializable attributes of every emitted argument |
+| `[]` | no event arguments |
+| `["index", "value"]` | only those attributes from a one-object event argument |
+| `[[], ["name"], None]` | for a three-argument event: none from the first, `name` from the second, and all of the third |
+
+Primitive values and arrays are forwarded as values rather than filtered by attribute name. Browser objects, DOM nodes, component references, functions, and cyclic structures are not meaningful server payloads; select the small serializable subset the Python handler actually needs.
+
+#### Transforming Events In The Browser
+
+`js_handler` receives the original Quasar or browser event arguments in the browser. Calling NiceGUI's injected `emit(...)` forwards only the transformed arguments to the Python `handler`:
+
+```python
+item_select.on(
+ "add",
+ handler=lambda event: print(event.args),
+ js_handler="(details) => emit({index: details.index, value: details.value})",
+)
+```
+
+Omit the Python handler for a client-only action, or omit `js_handler` to use NiceGUI's default `(...args) => emit(...args)` forwarding behavior. Since NiceGUI `2.18.0`, both can be supplied together. A `js_handler` may also decide not to call `emit`, in which case no Python callback runs for that occurrence.
+
+Events that pass imperative JavaScript callbacks require special care. For example, QSelect's `filter` event emits an input string plus `doneFn` and `abortFn` functions. Those functions cannot be serialized for later use by Python. Use NiceGUI's wrapper-supported filtering API, or consume such callbacks synchronously in browser-side JavaScript; do not treat them as ordinary server payloads.
+
+#### Modifiers And High-Frequency Events
+
+Dot suffixes use Vue's [event and key modifier rules](https://vuejs.org/guide/essentials/event-handling.html#event-modifiers):
+
+```python
+field.on("keydown.enter", submit)
+field.on("click.stop", handle_click)
+viewport.on("scroll.passive", handle_scroll, throttle=0.1)
+```
+
+NiceGUI separates listener options such as `capture`, `once`, and `passive`, event modifiers such as `stop`, `prevent`, and `self`, and key filters such as `enter`. The tagged [`EventListener.to_dict()` implementation](https://github.com/zauberzeug/nicegui/blob/v3.16.0/nicegui/event_listener.py) performs that classification before the frontend applies Vue's `withModifiers()` and `withKeys()` helpers. `throttle`, `leading_events`, and `trailing_events` regulate messages sent to Python; they do not throttle a client-only `js_handler` that never calls `emit`.
## Framework Boundary Model
@@ -15,9 +199,7 @@ A NiceGUI component is not a Python-rendered HTML fragment. Customization passes
Treat the generated DOM beneath a Quasar component as private implementation detail. Work through the highest owning layer that expresses the requirement.
-## How The APIs Map
-
-Use this map after confirming the exact API against the installed NiceGUI and bundled Quasar versions:
+## API Mapping Across Layers
| Requirement | NiceGUI surface | Underlying mechanic |
| --- | --- | --- |
@@ -28,7 +210,7 @@ Use this map after confirming the exact API against the installed NiceGUI and bu
| Imperative frontend action | a NiceGUI helper or `run_method(...)` | NiceGUI invokes a public method on the client component |
| Page placement or appearance | `.classes(...)`, `.style(...)`, or an application stylesheet | CSS applies to the rendered element; detached content needs its own class hook |
-Do not copy a Vue template into Python. Translate each part according to its owner: constructor data stays in Python, Quasar props go through `.props()`, emitted events go through callbacks or `.on()`, and named Vue slots go through NiceGUI's slot API.
+Constructor data remains in Python, Quasar props cross through `.props()`, emitted events cross through callbacks or `.on()`, and named Vue slots cross through NiceGUI's slot API. A Vue example in the Quasar documentation therefore maps to several distinct NiceGUI surfaces rather than to one copied template.
## State And Event Flow
@@ -40,48 +222,28 @@ Server-driven changes and user-driven changes cross a client-server boundary:
4. NiceGUI forwards registered events to Python handlers.
5. Python mutations return through bindings, wrapper helpers, or an explicit `update()`.
-Use wrapper helpers and bindings when available because they preserve NiceGUI's value model. Directly changing a Python collection or constructing a raw JavaScript object does not imply that the client receives the change.
+Wrapper helpers and bindings preserve NiceGUI's value model and schedule the corresponding client update. Directly changing a plain Python collection or constructing a raw JavaScript object does not itself imply that the client receives the change.
## Detached Content And Assets
-Some Quasar components render menus, dialogs, tooltips, and similar content outside the field or trigger's DOM subtree. A descendant CSS selector beneath the Python-created element will not reach that content. Use the component's documented popup or content class prop, then style that application-owned class separately.
+Some Quasar components render menus, dialogs, tooltips, and similar content outside the field or trigger's DOM subtree. A descendant CSS selector beneath the Python-created element will not reach that content. Component APIs expose props such as `popup-content-class` for assigning a separate class hook to detached content.
Icons and other externally defined visuals add another boundary: a valid Quasar icon name identifies an asset but does not load its font or stylesheet. Confirm both the naming convention and the application-level asset registration.
-## Component Customization Workflow
+## Versioned Sources
-Research the target component before generating code or CSS. Do not rely on a remembered NiceGUI or Quasar API, and do not mix source versions.
+The exact public surface depends on both the installed NiceGUI version and the Quasar version bundled with it. NiceGUI's tagged `package.json` records that pairing. The component details below describe NiceGUI `3.16.0` with Quasar `2.18.5`, as declared by [NiceGUI `v3.16.0` frontend dependencies](https://github.com/zauberzeug/nicegui/blob/v3.16.0/package.json).
-### Establish The Version Pair
+Four source levels answer different questions:
-1. Read the target project's lockfile or installed package metadata to identify its exact NiceGUI version.
-2. Open `package.json` at that NiceGUI tag and read the exact `quasar` dependency version.
-3. Use the NiceGUI tag for both NiceGUI sources and the matching `quasar-v` tag for both Quasar sources.
+| Source | Information it defines |
+| --- | --- |
+| NiceGUI component documentation | documented Python constructors, callbacks, methods, and examples |
+| NiceGUI wrapper source at the installed tag | normalization, validation, stored properties, bindings, updates, and the wrapped frontend component |
+| Quasar component API at the bundled tag | accepted props, emitted events, named slots, public methods, accessibility behavior, and warnings |
+| Quasar component source at the bundled tag | detailed runtime behavior behind that public API |
-The curated component sections below use NiceGUI `3.16.0` and Quasar `2.18.5`. The pairing comes from [NiceGUI `v3.16.0` frontend dependencies](https://github.com/zauberzeug/nicegui/blob/v3.16.0/package.json). Repeat the version check when the target application uses another NiceGUI release. Never infer compatibility from Quasar's latest release or use NiceGUI `main` with Quasar `dev`.
-
-### Research Four Sources
-
-Review these sources in order for the selected version pair:
-
-1. **NiceGUI documentation:** identify the supported Python API and documented examples for the component.
-2. **NiceGUI source code:** inspect constructor normalization, validation, props, bindings, events, helpers, and the wrapped frontend component.
-3. **Quasar documentation:** identify the wrapped component's public props, slots, events, methods, accessibility behavior, and documented warnings.
-4. **Quasar source code:** verify how those public APIs behave, especially popup mounting, model translation, event flow, rendering, and public methods.
-
-Use current upstream sources only when the target version is unavailable, and state that fallback explicitly. If the installed package differs from its tag, follow the installed implementation and record the difference.
-
-### Apply The Findings
-
-For every component section:
-
-1. Link the four version-matched sources under **Research Sources**.
-2. Summarize which layer owns the behavior under **Ownership Result**.
-3. Order the supported customization surfaces from highest-level NiceGUI API to lower-level Quasar or CSS mechanisms.
-4. Include an example only after the owning APIs are established.
-5. Curate a short caveat list from the four sources. Keep only constraints that change implementation, security, accessibility, performance, or testing decisions.
-
-If the requirement is purely visual after this ownership check, continue in [visual styling and CSS](./styling-and-customization.md).
+Links to `main`, `dev`, or the latest hosted documentation can describe a newer API than the installed package. Tagged NiceGUI and matching `quasar-v` links provide the version-specific definition.
## Using Slots In NiceGUI
@@ -91,9 +253,9 @@ NiceGUI creates a default slot for every element. Entering an element as a conte
These mechanics are defined by the tagged [`Element.add_slot()` implementation](https://github.com/zauberzeug/nicegui/blob/v3.16.0/nicegui/element.py), the [`Slot` context manager](https://github.com/zauberzeug/nicegui/blob/v3.16.0/nicegui/slot.py), and NiceGUI's [context-managed scoped-slot examples](https://github.com/zauberzeug/nicegui/blob/v3.16.0/website/documentation/content/table_documentation.py).
-### Prefer Context-Managed NiceGUI Elements
+### Context-Managed NiceGUI Elements
-Build slot content with ordinary NiceGUI elements by default:
+Ordinary NiceGUI elements can populate slot content:
```python
name_input = ui.input("Name")
@@ -102,46 +264,94 @@ with name_input.add_slot("prepend"):
ui.icon("person")
```
-Use nested context managers to express the component hierarchy. This preserves NiceGUI element identity, event registration, updates, deletion, and test visibility. Pass a raw Vue template to `add_slot(name, template)` only when the slot requires client-side structure that ordinary NiceGUI elements cannot express cleanly, such as a `v-for` that creates a variable number of sibling elements.
+Nested context managers express the component hierarchy while preserving NiceGUI element identity, event registration, updates, deletion, and test visibility. The `add_slot(name, template)` form accepts a raw Vue template for client-side structures such as a `v-for` that creates a variable number of sibling elements.
-### Use Scoped Props On The Client
+### Scoped Props On The Client
-A scoped slot receives a `props` object from its owning Vue component. Since NiceGUI `3.5.0`, NiceGUI elements inside a scoped-slot context can reference that object in dynamic `.props()` expressions and JavaScript event handlers:
+A scoped slot is a function whose argument is supplied by the component that renders the slot. Vue calls that argument the slot props; `props` is only NiceGUI's chosen local name for it. Since NiceGUI `3.5.0`, context-managed NiceGUI elements inside a scoped slot receive the current slot-props object as their frontend render context.
-- use `.props(":label=props.value")` or another component-supported prop to display a scoped value
-- use `.props("v-bind=props.itemProps")` when the slot provides a bundle of required attributes and handlers
-- use `.on(..., js_handler="... emit(...)", handler=...)` to transform and send serializable scoped values to Python
+The general `.props()` grammar and dynamic binding path are described under [Props](#props). In this context, the current scope object can be referenced by dynamic properties and JavaScript event handlers. For example:
+
+```python
+ui.badge().props(
+ ':label=props.label :color="props.selected ? \'primary\' : \'grey\'"'
+)
+```
+
+corresponds conceptually to this Vue template:
+
+```vue
+
+```
+
+Static `.props()` values do not have access to the slot scope. Only colon-prefixed expressions and NiceGUI JavaScript event handlers are evaluated with `props` in scope.
+
+#### Which `props.*` Names Exist
+
+There is no global catalog of `props.*` attributes. The owner of each named slot chooses the keys it passes when invoking that slot, so the available names can differ between components and between slots on the same component. Find them in this order:
+
+1. Open the wrapped component's version-matched Quasar API and inspect the **Slots** entry for the exact named slot.
+2. Use the slot's `scope` table as the public contract, including each value's type and whether it is data, state, or a callable.
+3. Inspect the version-matched Quasar source only when the API does not explain a bundle's contents or runtime behavior.
+
+For example, the [`QSelect` `option` slot API at Quasar `2.18.5`](https://github.com/quasarframework/quasar/blob/quasar-v2.18.5/ui/src/components/select/QSelect.json) exposes:
+
+| Expression | Meaning |
+| --- | --- |
+| `props.index` | index in the options array |
+| `props.opt` | original option from the `options` prop |
+| `props.label` | label after `option-label` processing |
+| `props.html` | whether the option content is marked as HTML |
+| `props.selected` | whether this option is selected |
+| `props.focused` | whether this option is the focused menu option |
+| `props.toggleOption` | function that adds or removes an option from the model |
+| `props.setOptionIndex` | function that changes the focused option index |
+| `props.itemProps` | object of computed props and listeners intended for the root `QItem` |
+
+The tagged [`QSelect` implementation](https://github.com/quasarframework/quasar/blob/quasar-v2.18.5/ui/src/components/select/QSelect.js) constructs `itemProps` with values such as `clickable`, `active`, `activeClass`, `manualFocus`, `focused`, `disable`, `tabindex`, `dense`, `dark`, `role`, `aria-selected`, `id`, `onClick`, and, when applicable, `onMousemove`. It is a behavior and accessibility bundle, not the original option object. Other QSelect slots expose different scopes: `no-option` only documents `inputValue`, while `selected-item` documents selection-oriented keys such as `index`, `opt`, `removeAtIndex`, `toggleOption`, and `tabindex`. A QTable body-cell slot's `props.value` is valid because QTable supplies `value`; that name should not be assumed in a QSelect option slot.
+
+#### Sending Scoped Values To Python
+
+NiceGUI also places the current slot object in scope while evaluating a `js_handler`. Use the event bridge's `emit(...)` function to select or transform JSON-serializable values before the Python callback runs:
+
+```python
+ui.button("Inspect").on(
+ "click",
+ handler=lambda event: print(event.args),
+ js_handler="() => emit({index: props.index, label: props.label})",
+)
+```
Scoped props exist only in the browser render context. They are not Python variables and cannot be read by a Python callback until a JavaScript handler emits the required values. Treat `innerHTML`, `v-html`, and raw template interpolation as untrusted HTML unless the source is explicitly sanitized.
-### Preserve The Slot Contract
+### Slot Contracts
-Replacing default slot content also replaces the wrapped component's default rendering. Preserve any documented slot-prop bundle that carries behavior. For example, a `QSelect` option slot must bind `props.itemProps` to its root item; otherwise the custom row can lose click selection, disabled state, focus, active state, and keyboard navigation. Keep one root element per virtual-scroll item unless the component documents how to mark additional siblings.
+Replacing default slot content also replaces the wrapped component's default rendering. Documented slot-prop bundles can carry behavior as well as data. For example, a `QSelect` option slot binds `props.itemProps` to its root item; without that binding, the custom row can lose click selection, disabled state, focus, active state, and keyboard navigation. Quasar's virtual-scroll contract expects one root element per item unless additional siblings carry its documented marker class.
## `ui.select`
-### Research Sources
+### Versioned Source Definitions
- **NiceGUI documentation:** [`ui.select` documentation source at `v3.16.0`](https://github.com/zauberzeug/nicegui/blob/v3.16.0/website/documentation/content/select_documentation.py)
- **NiceGUI source code:** [`Select` implementation at `v3.16.0`](https://github.com/zauberzeug/nicegui/blob/v3.16.0/nicegui/elements/select.py)
- **Quasar documentation:** [`QSelect` documentation source at `2.18.5`](https://github.com/quasarframework/quasar/blob/quasar-v2.18.5/docs/src/pages/vue-components/select.md)
- **Quasar source code:** [`QSelect` implementation at `2.18.5`](https://github.com/quasarframework/quasar/blob/quasar-v2.18.5/ui/src/components/select/QSelect.js)
-### Ownership Result
+### Layer Ownership
NiceGUI's `Select` wraps Quasar `QSelect` but owns important Python-side behavior. Its constructor handles options, labels, values, change callbacks, input filtering, new-value modes, multiple selection, clearing, validation, and key generation. Use those constructor parameters before adding equivalent Quasar props manually.
-### Customization Order
+### Exposed Surfaces
-1. Use `options`, `label`, `value`, `on_change`, `with_input`, `new_value_mode`, `multiple`, `clearable`, `validation`, and `key_generator` through the NiceGUI constructor.
-2. Use `.props()` for additional documented `QSelect` behavior such as field design, chips, option density, popup classes, popup positioning, or menu/dialog behavior.
-3. Use `.classes()` and Tailwind for the field's structural width and placement.
-4. Use named slots for prepend, append, loading, no-option, selected, or option content when props are insufficient.
-5. Preserve the documented scoped-slot props when replacing option content so Quasar retains selection and keyboard behavior.
+- The NiceGUI constructor exposes `options`, `label`, `value`, `on_change`, `with_input`, `new_value_mode`, `multiple`, `clearable`, `validation`, and `key_generator`.
+- `.props()` carries additional documented `QSelect` behavior such as field design, chips, option density, popup classes, popup positioning, and menu/dialog behavior.
+- `.classes()` attaches structural width, placement, and other CSS utilities to the field element.
+- Named slots provide prepend, append, loading, no-option, selected, and option content.
+- Scoped-slot props retain Quasar's selection and keyboard behavior when option content is replaced.
### Example: Custom Menu Options With A Scoped Slot
-`QSelect` supplies each option as `props.opt` and its interaction contract as `props.itemProps`. NiceGUI elements can consume both inside the slot context without a raw Vue template:
+`QSelect` supplies each option as `props.opt`, its processed label as `props.label`, and its interaction contract as `props.itemProps`. Because the complete interaction bundle needs Vue's object form of `v-bind`, use a raw slot template for the root item:
```python
from nicegui import ui
@@ -157,17 +367,24 @@ item_select = ui.select(
with item_select.add_slot("prepend"):
ui.icon("search")
-with item_select.add_slot("option"):
- with ui.item().props("v-bind=props.itemProps"):
- with ui.item_section().props("avatar"):
- ui.icon("inventory_2")
- with ui.item_section():
- ui.badge().props(":label=props.opt.label outline color=primary")
+item_select.add_slot(
+ "option",
+ r"""
+
+
+
+
+
+
+
+
+ """,
+)
```
-The `prepend` slot adds content around the field. The scoped `option` slot replaces every menu row with context-managed NiceGUI elements; the badge reads the browser-side option label through a dynamic Quasar prop. Keep `v-bind=props.itemProps` on the root `ui.item()` so the custom rendering retains the option's interaction and accessibility wiring.
+The `prepend` slot uses context-managed NiceGUI elements because it needs no scoped object spread. The raw `option` template is compiled by Vue, so `v-bind="props.itemProps"` forwards every computed property and listener to `QItem`; the badge reads the processed browser-side label. Keep that binding on the root item so the custom rendering retains the option's interaction and accessibility wiring.
-### Curated Caveats
+### Behavioral Caveats
These caveats are distilled from the four version-matched sources above:
@@ -177,34 +394,34 @@ These caveats are distilled from the four version-matched sources above:
- A multiple select has a list value. NiceGUI normalizes a non-list initial value, but application state should still use the intended list shape.
- `map-options` has a Quasar performance cost. Do not add it to NiceGUI's mapped options without confirming that the wrapper's value translation requires it.
- `display-value-html` and `options-html` can create cross-site scripting risk. When using `selected`, `selected-item`, or `option` slots, the application owns sanitization.
-- A custom `option` slot must bind `props.itemProps` to its root `ui.item()` so click, focus, active, disabled, and keyboard behavior remain connected.
+- A custom `option` slot must bind `props.itemProps` to its root `QItem` so click, focus, active, disabled, and keyboard behavior remain connected.
- Custom option slots use virtual scrolling. When one option renders multiple sibling elements, Quasar requires `q-virtual-scroll--with-prev` on every additional sibling.
- Buttons placed in `before`, `after`, `prepend`, or `append` field slots do not propagate clicks to the parent. A submit button in one of those slots needs its own submit handler.
- `QSelect` renders its popup outside the field. Style it through `popup-content-class`; do not assume a descendant selector beneath the field will reach it.
- Quasar switches between menu and dialog popup behavior by platform. Verify forced `behavior=menu` carefully on iOS when input filtering is enabled.
-Use `.on()` or `run_method()` only after confirming the event or method in the installed Quasar API. Prefer NiceGUI's `on_change`, `set_options()`, value bindings, and `is_showing_popup` when they cover the behavior.
+`.on()` and `run_method()` address events and methods defined by the installed Quasar API. NiceGUI's `on_change`, `set_options()`, value bindings, and `is_showing_popup` provide wrapper-managed equivalents for their respective behaviors.
## `ui.icon`
-### Research Sources
+### Versioned Source Definitions
- **NiceGUI documentation:** [`ui.icon` documentation source at `v3.16.0`](https://github.com/zauberzeug/nicegui/blob/v3.16.0/website/documentation/content/icon_documentation.py)
- **NiceGUI source code:** [`Icon` implementation at `v3.16.0`](https://github.com/zauberzeug/nicegui/blob/v3.16.0/nicegui/elements/icon.py)
- **Quasar documentation:** [`QIcon` documentation source at `2.18.5`](https://github.com/quasarframework/quasar/blob/quasar-v2.18.5/docs/src/pages/vue-components/icon.md)
- **Quasar source code:** [`QIcon` implementation at `2.18.5`](https://github.com/quasarframework/quasar/blob/quasar-v2.18.5/ui/src/components/icon/QIcon.js)
-### Ownership Result
+### Layer Ownership
NiceGUI's `Icon` is a thin `QIcon` wrapper. Its constructor exposes `name`, `size`, and `color`; the source forwards these to a `q-icon` element. Use Quasar's icon naming and asset rules for anything beyond those parameters.
-### Customization Order
+### Exposed Surfaces
-1. Choose an icon family that is actually loaded by the application.
-2. Pass the documented icon name, size, and color to `ui.icon()`.
-3. Use `.props()` for supported `QIcon` props such as `left`, `right`, or a custom render tag.
-4. Use `.classes()` for structural placement and an application class for stable visual variants.
-5. Use a static stylesheet for Material Symbol axes, state variants, custom webfonts, or repeated effects.
+- The application-loaded icon family determines which icon names can render.
+- `ui.icon()` accepts the documented icon name, size, and color.
+- `.props()` carries supported `QIcon` props such as `left`, `right`, and a custom render tag.
+- `.classes()` controls structural placement and can attach application-defined visual variants.
+- Static stylesheets define Material Symbol axes, state variants, custom webfonts, and repeated effects.
### Example
@@ -232,7 +449,7 @@ ui.icon(
}
```
-### Curated Caveats
+### Behavioral Caveats
These caveats are distilled from the four version-matched sources above:
@@ -245,15 +462,17 @@ These caveats are distilled from the four version-matched sources above:
- `QIcon` renders with `aria-hidden="true"`. For an action, use a semantic control such as `ui.button(icon=..., on_click=...)` and put the accessible name on that control; a tooltip is supplementary.
- Prefer `ui.icon(...).tooltip(...)` over manually constructing tooltip slot markup when NiceGUI's method covers the visual hint.
-## Completion Check
+## Related Reference Index
-Before accepting a special-component customization:
-
-1. Record the target NiceGUI version and its declared Quasar version.
-2. Link the version-matched NiceGUI documentation and source code.
-3. Link the version-matched Quasar documentation and source code.
-4. Identify constructor arguments, Quasar props, slots, Tailwind classes, and stylesheet rules separately.
-5. Confirm detached popup or external asset behavior where applicable.
-6. Keep the caveat list traceable to the four researched sources.
-7. Test keyboard interaction, focus, labels, and tooltips.
-8. Test the supported mobile, landscape desktop, and portrait desktop viewports.
\ No newline at end of file
+- [NiceGUI component documentation](https://nicegui.io/documentation): Python constructors, callbacks, bindings, and wrapper methods
+- [NiceGUI `Element` documentation](https://nicegui.io/documentation/element): common props, classes, styles, hierarchy, updates, and client methods
+- [NiceGUI generic events](https://nicegui.io/documentation/generic_events): `.on()`, event arguments, JavaScript handlers, and throttling
+- [NiceGUI binding documentation](https://nicegui.io/documentation/section_binding_properties): one-way and two-way Python property binding
+- [Quasar component documentation](https://quasar.dev/vue-components): per-component props, events, slots, and methods
+- [Quasar breakpoints](https://quasar.dev/style/breakpoints): viewport names and pixel thresholds
+- [Quasar spacing classes](https://quasar.dev/style/spacing): padding and margin class syntax and permutations
+- [Quasar visibility classes](https://quasar.dev/style/visibility): responsive, platform, orientation, and print visibility
+- [Quasar helper classes](https://quasar.dev/style/other-helper-classes): pointer, scrolling, sizing, rotation, and border helpers
+- [Tailwind CSS documentation](https://tailwindcss.com/docs): complete utility-class categories and variant syntax
+- [MDN CSS reference](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference): CSS properties accepted by `.style()` and application stylesheets
+- [MDN event reference](https://developer.mozilla.org/en-US/docs/Web/Events): native browser event names and behavior
\ No newline at end of file