Skip to content

SwitchableList

O componente SwitchableList é uma lista reordenável com suporte a seleção múltipla, busca, drag-and-drop e limites de seleção. É ideal para personalizações de colunas, seleção de filtros com limites e gerenciamento interativo de itens.

Exemplo

Personalize os itens conforme sua preferência. Você pode ordená-los arrastando com o mouse ou ocultá-los inativando o botão.
Nenhum item encontrado.
Clique para visualizar o código
vue
<script setup>
import LxSwitchableList from '@/components/LxSwitch/LxSwitchableList.vue';

const items = [
	{ id: 'item1', label: 'Item 1', checked: true },
	{ id: 'item2', label: 'Item 2', checked: true },
	{ id: 'item3', label: 'Item 3', checked: false },
	{ id: 'item4', label: 'Item 4', checked: false },
	{ id: 'item5', label: 'Item 5', checked: false }
];

const handleSave = (newItems) => {
	console.log('Items salvos:', newItems);
};
</script>

<template>
	<div style="border: 1px solid var(--lx-silver-100); border-radius: 8px; padding: 1rem; overflow: hidden">
		<LxSwitchableList id="example-list" :items="items" @save="handleSave" />
	</div>
</template>

Props

PropertyDescriçãoTipoPadrão
itemsArray de itens para exibiçãoArray[]
maxSelectionsLimite de items que podem ser selecionadosNumbernull
selectedOnTopMostra items selecionados no topoBooleantrue
showFooterExibe o footer com botõesBooleantrue
disabledDesabilita a ordenação e seleção dos itensBooleanfalse
sizeTamanho dos labels e switchesStringmd
headerConfigConfigurações do header (search, buttons)ObjectVer constantes
itemConfigConfigurações de propriedades dos itemsObjectVer constantes
textConfigTextos customizáveis do componenteObjectVer constantes
behaviorConfigComportamentos do componenteObjectVer constantes
containerClassClasses CSS customizadasString''

Emits

EventDescrição
@saveDisparado quando usuário clica em "Salvar"

Playground Interativo

Personalize as colunas conforme sua preferência
Nenhum item encontrado.
Status:
Items selecionados: 2 / 5
Comportamento drag: ✓ Habilitado
headerConfig
textConfig
behaviorConfig
Outras Props
Clique para visualizar o código
vue
<script setup>
import { reactive, ref, computed } from 'vue';
import LxSwitchableList from '@/components/LxSwitch/LxSwitchableList.vue';

const listRef = ref(null);

const mockItems = [
	{ id: 1, label: 'Coluna 1', checked: true, default: false },
	{ id: 2, label: 'Coluna 2', checked: true, default: false },
	{ id: 3, label: 'Coluna 3', checked: false, default: false },
	{ id: 4, label: 'Coluna 4', checked: false, default: true },
	{ id: 5, label: 'Coluna 5', checked: false, default: false }
];

const headerConfig = reactive({
	description: 'Personalize as colunas conforme sua preferência',
	searchable: true,
	searchPlaceholder: 'Pesquise por uma coluna',
	showRestoreDefault: true,
	showEnableAll: true,
	enableAllText: 'Ativar todos',
	enableAllTextSelected: 'filtrados'
});

const itemConfig = reactive({
	keyProperty: 'id',
	labelProperty: 'label',
	defaultProperty: 'default'
});

const textConfig = reactive({
	clearButtonText: 'Limpar',
	saveButtonText: 'Salvar',
	fixedBadgeText: 'padrão',
	disabledBadgeText: 'bloqueada',
	emptyMessage: 'Nenhum item encontrado.'
});

const behaviorConfig = reactive({
	draggable: true
});

const otherConfigs = reactive({
	selectedOnTop: true,
	maxSelections: null,
	showFooter: true,
	disabled: false,
	containerClass: '',
	size: 'md'
});

const displayItems = computed(() => listRef.value?.getCurrentItems() ?? mockItems);
const checkedCount = computed(() => displayItems.value.filter((i) => i.checked).length);

const configKey = computed(() => {
	return JSON.stringify({
		headerConfig,
		itemConfig,
		textConfig,
		behaviorConfig,
		otherConfigs
	});
});

const handleSave = (items) => {
	console.log('Items salvos:', items);
};
</script>

<template>
	<div>
		<div style="height: 500px; border: 2px solid var(--lx-silver-100); border-radius: 8px; padding: 1rem; overflow: hidden">
			<LxSwitchableList
				:key="configKey"
				ref="listRef"
				id="playground-list"
				:items="mockItems"
				:header-config="headerConfig"
				:item-config="itemConfig"
				:text-config="textConfig"
				:behavior-config="behaviorConfig"
				:selected-on-top="otherConfigs.selectedOnTop"
				:max-selections="otherConfigs.maxSelections"
				:show-footer="otherConfigs.showFooter"
				:disabled="otherConfigs.disabled"
				:container-class="otherConfigs.containerClass"
				:size="otherConfigs.size"
				@save="handleSave"
			/>
		</div>

		<div class="mt-3 p-3 bg-light rounded">
			<strong>Status:</strong>
			<div class="mt-2 small">
				<div>Items selecionados: {{ checkedCount }} / {{ displayItems.length }}</div>
				<div v-if="otherConfigs.maxSelections">Limite de seleções: {{ otherConfigs.maxSelections }}</div>
				<div>Comportamento drag: {{ behaviorConfig.draggable ? '✓ Habilitado' : '✗ Desabilitado' }}</div>
			</div>
		</div>
	</div>

	<div style="max-height: 600px; overflow-y: auto">
		<div class="border rounded p-3">
			<div class="mb-4">
				<h6 class="border-bottom pb-2 mb-3">
					<strong>headerConfig</strong>
				</h6>

				<div class="mb-3">
					<label class="form-label mb-1">description</label>
					<input v-model="headerConfig.description" type="text" class="form-control form-control-sm" placeholder="Deixe vazio para ocultar" />
				</div>

				<div class="mb-3">
					<label class="form-check-label">
						<input v-model="headerConfig.searchable" class="form-check-input" type="checkbox" />
						searchable
					</label>
				</div>

				<div class="mb-3">
					<label class="form-label mb-1">searchPlaceholder</label>
					<input v-model="headerConfig.searchPlaceholder" type="text" class="form-control form-control-sm" />
				</div>

				<div class="mb-3">
					<label class="form-check-label">
						<input v-model="headerConfig.showRestoreDefault" class="form-check-input" type="checkbox" />
						showRestoreDefault
					</label>
				</div>

				<div class="mb-3">
					<label class="form-check-label">
						<input v-model="headerConfig.showEnableAll" class="form-check-input" type="checkbox" />
						showEnableAll
					</label>
				</div>

				<div class="mb-3">
					<label class="form-label mb-1">enableAllText</label>
					<input v-model="headerConfig.enableAllText" type="text" class="form-control form-control-sm" />
				</div>

				<div class="mb-3">
					<label class="form-label mb-1">enableAllTextSelected</label>
					<input v-model="headerConfig.enableAllTextSelected" type="text" class="form-control form-control-sm" />
				</div>
			</div>

			<!-- Text Config -->
			<div class="mb-4">
				<h6 class="border-bottom pb-2 mb-3">
					<strong>textConfig</strong>
				</h6>

				<div class="mb-3">
					<label class="form-label mb-1">clearButtonText</label>
					<input v-model="textConfig.clearButtonText" type="text" class="form-control form-control-sm" />
				</div>

				<div class="mb-3">
					<label class="form-label mb-1">saveButtonText</label>
					<input v-model="textConfig.saveButtonText" type="text" class="form-control form-control-sm" />
				</div>

				<div class="mb-3">
					<label class="form-label mb-1">fixedBadgeText</label>
					<input v-model="textConfig.fixedBadgeText" type="text" class="form-control form-control-sm" />
				</div>
			</div>

			<!-- Behavior Config -->
			<div class="mb-4">
				<h6 class="border-bottom pb-2 mb-3">
					<strong>behaviorConfig</strong>
				</h6>

				<div class="mb-3">
					<label class="form-check-label">
						<input v-model="behaviorConfig.draggable" class="form-check-input" type="checkbox" />
						draggable (Drag-and-drop)
					</label>
				</div>
			</div>

			<!-- Other Props -->
			<div class="mb-4">
				<h6 class="border-bottom pb-2 mb-3">
					<strong>Outras Props</strong>
				</h6>

				<div class="mb-3">
					<label class="form-check-label">
						<input v-model="otherConfigs.selectedOnTop" class="form-check-input" type="checkbox" />
						selectedOnTop
					</label>
				</div>

				<div class="mb-3">
					<label class="form-label mb-1">maxSelections</label>
					<input v-model.number="otherConfigs.maxSelections" type="number" class="form-control form-control-sm" placeholder="null = sem limite" min="0" />
				</div>

				<div class="mb-3">
					<label class="form-check-label">
						<input v-model="otherConfigs.showFooter" class="form-check-input" type="checkbox" />
						showFooter
					</label>
				</div>

				<div class="mb-3">
					<label class="form-check-label">
						<input v-model="otherConfigs.disabled" class="form-check-input" type="checkbox" />
						disabled (bloqueia seleção e reordenação)
					</label>
				</div>

				<div class="mb-3">
					<label class="form-label mb-1">containerClass</label>
					<input v-model="otherConfigs.containerClass" type="text" class="form-control form-control-sm" placeholder="Classes CSS customizadas" />
				</div>

				<div class="mb-3">
					<label class="form-label mb-1">size</label>
					<select v-model="otherConfigs.size" class="form-select form-select-sm">
						<option value="sm">Pequeno (sm)</option>
						<option value="md">Médio (md)</option>
						<option value="lg">Grande (lg)</option>
					</select>
				</div>
			</div>
		</div>
	</div>
</template>

<style scoped>
::-webkit-scrollbar {
	width: 6px;
}

::-webkit-scrollbar-track {
	background: #f1f1f1;
}

::-webkit-scrollbar-thumb {
	background: #888;
	border-radius: 3px;
}

::-webkit-scrollbar-thumb:hover {
	background: #555;
}
</style>

Casos de Uso

O SwitchableList é útil em diversos cenários, como:

  • Personalização de Colunas: Permitir usuários escolherem quais colunas visualizar em tabelas
  • Filtros com Limite: Selecionar múltiplos filtros com um limite máximo de seleções
  • Reordenação de Itens: Permitir drag-and-drop para reordenar items
  • Gerenciamento de Permissões: Atribuir múltiplas permissões com controle visual
  • Seleção de Features: Ativar/desativar features de um sistema

Desenvolvido pelo time Linx Microvix