ExpandableContainer
Resumo
O LxExpandableContainer é um container que pode ser expandido para ocupar toda a tela (ou um container pai específico). Ao expandir, o conteúdo é movido via Teleport para o elemento alvo (padrão: body), travando o scroll da página. Suporta fechamento por tecla Esc, botão do navegador (popstate) e controle programático.
Expansão padrão (teleport para body)
O container ocupa toda a viewport. Feche com Esc, com o botão de voltar do navegador ou com o botão de recolher.
Conteúdo expandido para tela inteira via Teleport para o body.
Expansão sobre um container específico
Quando teleportTo aponta para um elemento específico, o container expandido assume exatamente as dimensões e posição desse elemento na viewport.
Este é o container alvo (#scoped-expand-target). O conteúdo expandido cobrirá exatamente esta área.
Cobrindo exatamente #scoped-expand-target.
Controle programático via ref
Usando os métodos expostos expand(), collapse() e toggle() via ref do componente.
Este container foi aberto programaticamente via containerRef.value.expand().
Clique para visualizar o código
vue
<script setup lang="ts">
import { ref } from 'vue';
import { LxExpandableContainer, LxButton } from '@lde/lxcomponents';
const isExpanded = ref(false);
const isExpandedScoped = ref(false);
const isExpandedProgrammatic = ref(false);
const containerRef = ref<InstanceType<typeof LxExpandableContainer> | null>(null);
const expandViaRef = (): void => containerRef.value?.expand();
const collapseViaRef = (): void => containerRef.value?.collapse();
const toggleViaRef = (): void => containerRef.value?.toggle();
</script>
<template>
<div class="example-wrapper">
<section class="example-section">
<h4>Expansão padrão (teleport para body)</h4>
<p>O container ocupa toda a viewport. Feche com <kbd>Esc</kbd>, com o botão de voltar do navegador ou com o botão de recolher.</p>
<LxButton id="btn-expand" label="Expandir conteúdo" icon="fas fa-expand-alt" @click="isExpanded = true" />
<LxExpandableContainer id="example-expandable" v-model="isExpanded" title="Visualização expandida" close-label="Recolher">
<div class="expandable-content">
<p>Conteúdo expandido para tela inteira via <code>Teleport</code> para o <code>body</code>.</p>
<LxButton id="btn-collapse" label="Recolher" severity="secondary" icon="fas fa-compress-alt" @click="isExpanded = false" />
</div>
</LxExpandableContainer>
</section>
<section class="example-section">
<h4>Expansão sobre um container específico</h4>
<p>Quando <code>teleportTo</code> aponta para um elemento específico, o container expandido assume exatamente as dimensões e posição desse elemento na viewport.</p>
<div id="scoped-expand-target" class="scoped-container">
<p>Este é o container alvo (<code>#scoped-expand-target</code>). O conteúdo expandido cobrirá exatamente esta área.</p>
<LxButton id="btn-expand-scoped" label="Expandir neste container" icon="fas fa-expand-alt" size="sm" @click="isExpandedScoped = true" />
<LxExpandableContainer
id="example-expandable-scoped"
v-model="isExpandedScoped"
title="Expandido sobre o container"
close-label="Fechar"
teleport-to="#scoped-expand-target"
>
<div class="expandable-content">
<p>Cobrindo exatamente <code>#scoped-expand-target</code>.</p>
<LxButton id="btn-collapse-scoped" label="Fechar" severity="secondary" icon="fas fa-compress-alt" size="sm" @click="isExpandedScoped = false" />
</div>
</LxExpandableContainer>
</div>
</section>
<section class="example-section">
<h4>Controle programático via ref</h4>
<p>Usando os métodos expostos <code>expand()</code>, <code>collapse()</code> e <code>toggle()</code> via <code>ref</code> do componente.</p>
<div class="btn-row">
<LxButton id="btn-ref-expand" label="expand()" icon="fas fa-expand-alt" size="sm" @click="expandViaRef" />
<LxButton id="btn-ref-toggle" label="toggle()" icon="fas fa-random" size="sm" severity="secondary" @click="toggleViaRef" />
<LxButton id="btn-ref-collapse" label="collapse()" icon="fas fa-compress-alt" size="sm" severity="secondary" @click="collapseViaRef" />
</div>
<LxExpandableContainer id="example-expandable-ref" ref="containerRef" v-model="isExpandedProgrammatic" title="Controlado por ref" close-label="Fechar">
<div class="expandable-content">
<p>Este container foi aberto programaticamente via <code>containerRef.value.expand()</code>.</p>
<LxButton id="btn-ref-close" label="Fechar via collapse()" severity="secondary" icon="fas fa-compress-alt" @click="collapseViaRef" />
</div>
</LxExpandableContainer>
</section>
</div>
</template>
<style scoped>
.example-wrapper {
display: flex;
flex-direction: column;
gap: 2rem;
}
.example-section {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.example-section h4 {
font-weight: 600;
margin: 0;
}
.example-section p {
margin: 0;
}
.scoped-container {
position: relative;
border: 1px dashed var(--lx-border-color, #ccc);
border-radius: 0.5rem;
padding: 1rem;
min-height: 140px;
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.btn-row {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}
.expandable-content {
display: flex;
flex-direction: column;
gap: 1rem;
padding: 1rem;
}
</style>Propriedades
| Nome | Descrição | Tipo | Padrão |
|---|---|---|---|
| id | Identificador base do container | String | 'lx-expandable-container' |
| modelValue | Controla o estado expandido/recolhido via v-model | Boolean | false |
| title | Título exibido no cabeçalho quando expandido. Quando vazio, o cabeçalho não é renderizado | String | '' |
| closeLabel | Texto do botão de recolher exibido no cabeçalho | String | 'Recolher' |
| teleportTo | Seletor CSS do elemento alvo do Teleport quando expandido | String | 'body' |
| disabled | Desabilita a alternância de estado | Boolean | false |
Eventos
| Nome | Descrição | Payload |
|---|---|---|
| update:modelValue | Emitido ao alterar o estado expandido/recolhido | Boolean |
| expand:region | Emitido ao expandir o container | { targetId: string | null } |
| collapse:region | Emitido ao recolher o container | { targetId: string | null } |
Slots
| Nome | Descrição |
|---|---|
| default | Conteúdo exibido dentro do container, tanto no estado recolhido quanto no expandido |
Métodos expostos
O componente expõe os seguintes métodos via ref (usando defineExpose):
| Nome | Descrição |
|---|---|
| toggle() | Alterna entre expandido e recolhido |
| expand() | Expande o container |
| collapse() | Recolhe o container |
Comportamento de expansão
- Quando expandido com
teleportTo="body"(padrão), o container é posicionado comofixedcobrindo toda a viewport (inset: 0) e o scroll dobodyé travado. - Quando
teleportToaponta para um seletor CSS específico, o container mede ogetBoundingClientRect()do elemento alvo ao expandir e aplicatop/left/width/heightcomo inline style — cobrindo exatamente a área daquele elemento na viewport. A medição é atualizada automaticamente viaResizeObservere listeners deresize/scrollenquanto o container estiver expandido. - O
Teleporté ativado somente quando o container está expandido; no estado recolhido, o conteúdo permanece no lugar original do DOM. - O fechamento via
Esce o botão de voltar do navegador (popstate) são capturados automaticamente enquanto o container estiver expandido.
LxComponents