Collapsible panels. Several can be open at once unless accordion = TRUE.
Usage
el_collapse(
id = NULL,
items = list(),
value = character(0),
accordion = FALSE,
expand_icon_position = "right",
before_collapse = NULL,
session = NULL
)
update_el_collapse(
session = shiny::getDefaultReactiveDomain(),
id,
value = NULL,
accordion = NULL,
expand_icon_position = NULL,
before_collapse = NULL
)Arguments
- id
Collapse ID. Auto-generated UUID if
NULL.- items
A list of panels, each an
el_collapse_item()– or a named list with the same fields:- name
Unique panel identifier (string). Required.
- title
Panel header text. Required.
- content
Panel body. Any tag or tagList, including this package's own components.
- disabled
Whether the header is disabled. Default
FALSE.- icon
The expand icon, by name (default
"ArrowRight"), or a tag.
- value
Character vector of initially open panel names. In accordion mode only the first is used.
- accordion
Single-open accordion mode. Default
FALSE.- expand_icon_position
Where each header's icon sits:
"right"(the default) or"left".- before_collapse
JS()functionfunction(name), run before a panel opens or closes: returnfalse, or a promise that resolves tofalse, to keep it as it is.- session
In
el_collapse(), deprecated: inside a module, wrapidinns(), as for any Shiny input; a session given here namespacesidonce more, with a warning. Inupdate_el_collapse(), the Shiny session, the current one by default, as forshiny::updateTextInput().
Details
Rendered as plain markup carrying Element's own classes, driven by a Shiny
input binding rather than a Vue instance. That is what lets a panel hold
other components from this package: a Vue instance mounted here would
rebuild the DOM underneath them, detaching them from the server. See
.claude/docs/lessons.md.
Shiny inputs
input$<id> – character vector of open panel names, reported on load and on
every change. Empty when all are closed, which Shiny reports as NULL.
Updating from the server
Server-side update for el_collapse(): the open panels, accordion,
expand_icon_position and before_collapse (NA for none).
update_el_collapse() is called for its side effect and returns NULL invisibly.
Examples
el_collapse(
"col1",
items = list(
list(name = "p1", title = "Panel 1", content = shiny::tags$p("Content 1")),
list(name = "p2", title = "Panel 2", content = shiny::tags$p("Content 2"))
),
value = "p1"
)
#> <div id="col1" class="el-collapse el-collapse-icon-position-right" data-el-collapse="true" data-accordion="false">
#> <div class="el-collapse-item is-active" data-el-name="p1">
#> <div id="col1-head-p1" role="button" tabindex="0" aria-expanded="true" aria-controls="col1-content-p1" aria-describedby="col1-content-p1" class="el-collapse-item__header is-active">
#> <span class="el-collapse-item__title">Panel 1</span>
#> <i class="el-icon el-collapse-item__arrow is-active" data-el-icon="ArrowRight"></i>
#> </div>
#> <div id="col1-content-p1" role="region" aria-hidden="false" aria-labelledby="col1-head-p1" class="el-collapse-item__wrap">
#> <div class="el-collapse-item__content">
#> <p>Content 1</p>
#> </div>
#> </div>
#> </div>
#> <div class="el-collapse-item" data-el-name="p2">
#> <div id="col1-head-p2" role="button" tabindex="0" aria-expanded="false" aria-controls="col1-content-p2" aria-describedby="col1-content-p2" class="el-collapse-item__header">
#> <span class="el-collapse-item__title">Panel 2</span>
#> <i class="el-icon el-collapse-item__arrow" data-el-icon="ArrowRight"></i>
#> </div>
#> <div id="col1-content-p2" role="region" aria-hidden="true" aria-labelledby="col1-head-p2" class="el-collapse-item__wrap" style="display:none">
#> <div class="el-collapse-item__content">
#> <p>Content 2</p>
#> </div>
#> </div>
#> </div>
#> </div>
# A panel can hold other components
el_collapse(
"col2",
items = list(
list(
name = "f",
title = "Filters",
content = shiny::tagList(el_input("q"), el_switch("live"))
)
)
)
#> <div id="col2" class="el-collapse el-collapse-icon-position-right" data-el-collapse="true" data-accordion="false">
#> <div class="el-collapse-item" data-el-name="f">
#> <div id="col2-head-f" role="button" tabindex="0" aria-expanded="false" aria-controls="col2-content-f" aria-describedby="col2-content-f" class="el-collapse-item__header">
#> <span class="el-collapse-item__title">Filters</span>
#> <i class="el-icon el-collapse-item__arrow" data-el-icon="ArrowRight"></i>
#> </div>
#> <div id="col2-content-f" role="region" aria-hidden="true" aria-labelledby="col2-head-f" class="el-collapse-item__wrap" style="display:none">
#> <div class="el-collapse-item__content">
#> <div id="q" data-shiny-vue style="display: contents">
#> <script type="text/x-template" data-shiny-vue-template><div id="q_container" style="display: contents">
#> <el-input v-model="value" :type="type" :disabled="disabled" :readonly="readonly" :clearable="clearable" :show-password="showPassword" :show-word-limit="showWordLimit" :autosize="autosize" :prefix-icon="prefixIcon" :suffix-icon="suffixIcon" @change="handleChange" :size="size === null ? undefined : size" :maxlength="maxlength === null ? undefined : maxlength" :rows="rows === null ? undefined : rows" :placeholder="placeholder === null ? undefined : placeholder" :label="label === null ? undefined : label" :autocomplete="autocomplete === null ? undefined : autocomplete" :autofocus="autofocus === null ? undefined : autofocus" :name="name === null ? undefined : name" :form="form === null ? undefined : form" :minlength="minlength === null ? undefined : minlength" :max="max === null ? undefined : max" :min="min === null ? undefined : min" :step="step === null ? undefined : step" :resize="resize === null ? undefined : resize" :tabindex="tabindex === null ? undefined : tabindex" :validate-event="validateEvent === null ? undefined : validateEvent" @input="elEmitInput" @blur="elEmitBlur" @focus="elEmitFocus" @clear="elEmitClear" @compositionend="elEmitCompositionend" @compositionstart="elEmitCompositionstart" @compositionupdate="elEmitCompositionupdate" @keydown="elEmitKeydown" @mouseenter="elEmitMouseenter" @mouseleave="elEmitMouseleave" :aria-label="ariaLabel === null ? undefined : ariaLabel" :clear-icon="clearIcon === null ? undefined : clearIcon" :count-graphemes="countGraphemes === null ? undefined : countGraphemes" :formatter="formatter === null ? undefined : formatter" :input-style="inputStyle === null ? undefined : inputStyle" :inputmode="inputmode === null ? undefined : inputmode" :parser="parser === null ? undefined : parser" :word-limit-position="wordLimitPosition === null ? undefined : wordLimitPosition"></el-input>
#> </div></script>
#> <script type="application/json" data-shiny-vue-options>{"options":{"data":{"value":"","type":"text","disabled":false,"readonly":false,"clearable":false,"showPassword":false,"showWordLimit":false,"autosize":false,"prefixIcon":null,"suffixIcon":null,"size":null,"maxlength":null,"rows":null,"placeholder":null,"label":null,"autocomplete":null,"autofocus":null,"name":null,"form":null,"minlength":null,"max":null,"min":null,"step":null,"resize":null,"tabindex":null,"validateEvent":null,"ariaLabel":null,"clearIcon":null,"countGraphemes":null,"formatter":null,"inputStyle":null,"inputmode":null,"parser":null,"wordLimitPosition":null},"methods":{"elEmitInput":"function() { window.shinyVue.emit('q', 'input', arguments); }","elEmitBlur":"function() { window.shinyVue.emit('q', 'blur', arguments); }","elEmitFocus":"function() { window.shinyVue.emit('q', 'focus', arguments); }","elEmitClear":"function() { window.shinyVue.emit('q', 'clear', arguments); }","elEmitCompositionend":"function() { window.shinyVue.emit('q', 'compositionend', arguments); }","elEmitCompositionstart":"function() { window.shinyVue.emit('q', 'compositionstart', arguments); }","elEmitCompositionupdate":"function() { window.shinyVue.emit('q', 'compositionupdate', arguments); }","elEmitKeydown":"function() { window.shinyVue.emit('q', 'keydown', arguments); }","elEmitMouseenter":"function() { window.shinyVue.emit('q', 'mouseenter', arguments); }","elEmitMouseleave":"function() { window.shinyVue.emit('q', 'mouseleave', arguments); }","handleChange":"function(value) { }"}},"input":"value","rate":{"policy":"debounce","delay":250},"type":null,"use":["shinyElement.plugin"],"evals":["options.methods.elEmitInput","options.methods.elEmitBlur","options.methods.elEmitFocus","options.methods.elEmitClear","options.methods.elEmitCompositionend","options.methods.elEmitCompositionstart","options.methods.elEmitCompositionupdate","options.methods.elEmitKeydown","options.methods.elEmitMouseenter","options.methods.elEmitMouseleave","options.methods.handleChange"]}</script>
#> </div>
#> <div id="live" data-shiny-vue style="display: contents">
#> <script type="text/x-template" data-shiny-vue-template><div id="live_container" style="display: contents">
#> <el-switch v-model="value" :disabled="disabled" :active-text="activeText" :inactive-text="inactiveText" :style="{ '--el-switch-on-color': activeColor || undefined, '--el-switch-off-color': inactiveColor || undefined, '--el-switch-border-color': borderColor || undefined }" :active-value="activeValue" :inactive-value="inactiveValue" @change="handleChange" :width="width === null ? undefined : width" :name="name === null ? undefined : name" :validate-event="validateEvent === null ? undefined : validateEvent" :active-action-icon="activeActionIcon === null ? undefined : activeActionIcon" :active-icon="activeIcon === null ? undefined : activeIcon" :aria-label="ariaLabel === null ? undefined : ariaLabel" :before-change="beforeChange === null ? undefined : beforeChange" :border-color="borderColor === null ? undefined : borderColor" :inactive-action-icon="inactiveActionIcon === null ? undefined : inactiveActionIcon" :inactive-icon="inactiveIcon === null ? undefined : inactiveIcon" :inline-prompt="inlinePrompt === null ? undefined : inlinePrompt" :loading="loading === null ? undefined : loading" :size="size === null ? undefined : size" :tabindex="tabindex === null ? undefined : tabindex"></el-switch>
#> </div></script>
#> <script type="application/json" data-shiny-vue-options>{"options":{"data":{"value":false,"disabled":false,"activeText":"","inactiveText":"","activeColor":"","inactiveColor":"","activeValue":true,"inactiveValue":false,"width":null,"name":null,"validateEvent":null,"activeActionIcon":null,"activeIcon":null,"ariaLabel":null,"beforeChange":null,"borderColor":null,"inactiveActionIcon":null,"inactiveIcon":null,"inlinePrompt":null,"loading":null,"size":null,"tabindex":null},"methods":{"handleChange":"function(value) { }"}},"input":"value","rate":null,"type":null,"use":["shinyElement.plugin"],"evals":["options.methods.handleChange"]}</script>
#> </div>
#> </div>
#> </div>
#> </div>
#> </div>
if (interactive()) {
# inside a server function
observeEvent(input$go, {
update_el_collapse(session, "panels", value = "filters")
})
}