Changes in version 0.3.1 (2026-11-04) A smaller package, ready for CRAN, and the fixes and additions since 0.3.0: each level of a cascader's path as an input, on on any event, el_form_field(options =). New features - el_cascader(level_inputs =) and el_cascader_panel(level_inputs =) report each level of the path as an input of its own, under the ids given -- level_inputs = c("compound", "study", "analysis") gives input$compound, input$study and input$analysis beside the path in input$; in a module, ns(c(...)). They follow the path on load, when the user picks and when update_el_cascader() sets it, and each notifies its observers only when its own level changes. NULL, the default, reports the path alone. - The installed package is smaller, 4.3 MB where it was 5.4 MB, with nothing given up a page uses: - Element Plus's eleven locales used most (English, Chinese, Japanese, Korean, French, German, Spanish, Portuguese, Russian) stay files; the other 56 are packed in one archive and taken out into the session's temporary directory the first time one is used. el_locales() still lists all 67. - Vue's development build (el_page(dev = TRUE)) is in the package's sources but not in the package built for CRAN, which loads it from the unpkg CDN. - The Forms, Dashboards, Putting Components Together and "What works" articles are on the website only, no longer vignettes. Bug fixes - el_form_field() takes options, Element's name for the choices, as el_select() does. Given before, it went through ... to the select as its own options prop -- records with no value or label -- and the dropdown opened onto blank entries; the Forms article's examples wrote it so. tools/article-shots.R now opens every dropdown of every example and reports blank options. - el_cascader(value =) and update_el_cascader(value =) given a path of one level -- "c1", with checkStrictly -- sent it as a string rather than an array, which level_inputs read as no path. - on given an event the component handles itself -- change on el_cascader(), el_select(), el_input(), el_date_picker(), el_slider() and the other value components, select on el_menu(), node-click and check on el_tree(), selection-change on el_table(), 24 in all -- wrote both handlers into one attribute Vue could not compile, and the component did not mount. Both now run, the component's own first. Documentation - use_element()'s example runs as it stands, and el_calendar_events() has one. Like el_table_data(), it reads the data the server keeps for a data component; both now read it alike, rather than the calendar's through the table's. - An "Architecture" article draws the two layers: the Vue layer, from vue_app() to the browser and back, and the Element layer on top of it -- its kinds of component, the events registry, updates and containers. - Examples put back what they change: the sales dashboard restores par() after its plot, and el_locale_dependency()'s example the options() it sets. The title and description write 'shiny' as the package is named. Changes in version 0.3.0 The Vue layer, reviewed against vueR, vuer, reactR, shiny.react and shinyreact for three things: all of Vue, all of Shiny and shinyjs, and libraries other than Element built on it. Breaking changes - Updates and method calls are sent with the flush, as Shiny's own update*Input() are -- after the outputs the same observers recalculated -- where they were sent at once: every update_el_*(), call_el(), update_vue(), call_vue(), el_load_children() and vue_answer(). A component an observer re-renders and updates now gets the update once drawn; before, the update reached the component being replaced and was lost. An update made before a long computation in the same observer shows after it, as Shiny's do: flush_vue() sends it at once. update_el_progress() is still sent at once, as withProgress() is. - The methods the package generates to forward events are svEmit* and svOn* (were elEmit*, elOn*), as they now belong to the Vue layer. New features - flush_vue({ ... }) sends the updates made in it, and those queued before, at once; flush_vue() alone sends what is queued. - el_button(task = TRUE): a task button, as bslib's input_task_button() -- Element's loading state from the click, set in the browser, until the server has handled the click, or, bound with bslib::bind_task_button(), until an ExtendedTask is done. It speaks bslib's protocol, so bslib's own server code drives it; folded into a tooltip it works too. - Shiny UI inside a Vue template -- an input, an output, an htmlwidget, a conditionalPanel(), a component of this package -- is kept out of Vue's compiling and moved into place, so v-if and v-for can show and hide it: it keeps its binding and the user's input, and an output hidden this way waits, as one in a hidden tab does. Before, it lost its binding once Vue drew it again, an htmlwidget lost its data, and a component function in a vue_app() template broke the template. - update_vue(insert =, replace =, delete =, at =, key =) changes a list field in place, by position or by a key field, and update_vue(set =) sets values by path ("items[3].done"): a long list or a deep object is not sent whole. The table's and the calendar's insert, replace and delete are built on it. - vue_app(type =, rate =): an input handler and a rate policy for the value, as Shiny's inputs and el_widget() have. - vue_app(events =, on =): events of the template's root forwarded as input$_, and handlers of one's own -- the machinery Element's components use, now in the Vue layer for any library. - vue_app(use = JS("{ install(app) { ... } }")): a plugin written in R, the way to reach app.config. - Templates read $inputs. (another input's value), $errors. (a data output's error) and $busy (the server working), beside $recalculating.. - Composables for setup(), as shinyreact's hooks: shinyVue.useInput(name, initial), shinyVue.useInputValue(name), shinyVue.useOutput(id) (its value, recalculating and error) and shinyVue.useBusy(). - Input messages to a component folded into another -- which has no binding of its own -- reach it. Documentation - "Shiny integration": when an update arrives and flush_vue(), task buttons, changing data in place, what a template can read of Shiny, the composables, Shiny UI inside a template. Changes in version 0.2.0 Breaking changes Not yet on CRAN, so the API may still move without a deprecation; from the first CRAN release on, a change like these goes through one first. - Components report their value, the user's deliberate actions and the server's requests; Element's other events only when asked for. A typed character, a hover, a focus or a dropdown opening each sent a message to the server, and most apps never read them: an input, a select, a slider, a date picker and a tooltip sent 66 messages for one ordinary use, 3 of them read; they now send 3. Ask for an event with the component's events, by Element's name in snake_case -- el_tree(events = "node_drop") reports input$_node_drop. Code reading an event input that is no longer reported unasked -- input$x_focus, input$x_visible_change, a dialog's input$x_open -- needs it asked for. - el_on() is gone: el_table(events =) does what it did, the input always input$_ -- a name of one's own was reported outside a module's namespace. - el_tree() takes Element Plus's names: its field map is props = list(label =, children =, disabled =, isLeaf =, class =), as el_tree_select() and el_tree_v2() take it, where it was label_field, children_field, disabled_field, is_leaf_field and class_field; its keys are default_expanded_keys and default_checked_keys, as el_tree_v2()'s, where they were expanded and checked -- in update_el_tree() too, which can now change props. input$_checked is unchanged. - Element Plus's names where they differed for no reason: el_menu(default_active =), as Element's default-active, was active; el_upload(data =), Element's data, was extra_data -- the fields Element's own request sends with action, which Shiny's upload does not send; input$_close of el_tag() and el_alert(), Element's close event, was _closed (a dialog's _closed is Element's closed, after the animation); input$_page_size of el_pagination(), as its page_size, was _size; and el_tour()'s open state is visible, as the dialog's, drawer's, tooltip's and popover's, where it was open. The update_el_*() functions follow. New features - el_events() lists every input a component reports -- its value, its requests, the events it reports unasked and those it can be asked for -- from one registry, which also checks each component's events (a name it does not have is an error listing them) and writes each help page's "Shiny inputs" table. - on, on every component: a handler of your own for any event -- Element's, or a DOM event with Vue's modifiers -- as DT's callback and reactable's onClick let one. on = list("keyup.enter" = JS("function(report, e) { report('enter', e.target.value); }")) reports input$_enter, namespaced in a module as the id is. An event the component reports too runs both. - A keyboard event sends its key, list(key, code, ctrl, shift, alt, meta), rather than TRUE. - el_tabs() and update_el_tabs() take value as well as selected, as el_select() does. Bug fixes - A config provider inside another takes what it leaves unset from the outer one -- a card's shadow, the size of a component drawn later. - insert_el_tab() inserts the pane into tabs whose id has a dot or a colon, as Shiny's ids may: the selector was not escaped. - A component folded into another keeps its id where Element puts it -- a button's