MeUserFeedbackModal
Modal de feedback com suporte a perguntas de range (estrelas interativas), texto, textarea e email. Controla respostas internamente e expõe via v-model:answers.
Playground
Importação
vue
<script setup>
import { MeUserFeedbackModal } from '@me/ui-vue3'
import type { FeedbackQuestion } from '@me/ui-vue3'
</script>vue
<script>
import { MeUserFeedbackModal } from '@me/ui-vue2'
export default {
components: { MeUserFeedbackModal }
}
</script>Uso Básico
Um modal de feedback simples com uma pergunta de estrelas e um campo de comentário opcional.
vue
<script setup>
import { ref } from 'vue'
import type { FeedbackQuestion } from '@me/ui-vue3'
const isOpen = ref(false)
const questions: FeedbackQuestion[] = [
{
key: 'satisfaction',
label: 'Como você avalia nossa plataforma?',
type: 'range',
required: true,
minLabel: 'Insatisfeito',
maxLabel: 'Satisfeito',
},
{
key: 'comment',
label: 'Deixe um comentário (opcional)',
type: 'textarea',
required: false,
placeholder: 'Compartilhe suas sugestões...',
},
]
function handleSubmit(data) {
console.log(data) // { satisfaction: 4, comment: '...' }
isOpen.value = false
}
</script>
<template>
<MeUserFeedbackModal
:visible="isOpen"
title="Como foi sua experiência?"
:questions="questions"
@submit="handleSubmit"
@close="isOpen = false"
/>
</template>Múltiplas Perguntas de Range
Combine várias perguntas de estrelas para avaliar diferentes aspectos.
vue
<template>
<MeUserFeedbackModal
:visible="isOpen"
title="Avalie cada aspecto"
:questions="[
{ key: 'design', label: 'Como você avalia o design?', type: 'range', required: true },
{ key: 'usability', label: 'Como você avalia a usabilidade?', type: 'range', required: true },
{ key: 'performance', label: 'Como você avalia a performance?', type: 'range', required: true },
]"
@submit="handleSubmit"
@close="isOpen = false"
/>
</template>Tipos de Campo Misturados
Use type: 'text', 'email' e 'textarea' em conjunto com perguntas de range.
vue
<template>
<MeUserFeedbackModal
:visible="isOpen"
title="Formulário de Feedback"
bodyMaxHeight="60vh"
:questions="[
{ key: 'overall', label: 'Avaliação geral', type: 'range', required: true },
{ key: 'name', label: 'Seu nome', type: 'text', required: true, placeholder: 'Digite seu nome' },
{
key: 'email',
label: 'Seu e-mail',
type: 'email',
required: true,
placeholder: 'voce@exemplo.com',
hint: 'Usaremos apenas para entrar em contato.',
},
{
key: 'suggestion',
label: 'O que podemos melhorar?',
type: 'textarea',
required: false,
rows: 3,
},
]"
@submit="handleSubmit"
@close="isOpen = false"
/>
</template>Com Descrição
Use a prop description para exibir um texto introdutório com destaque visual acima das perguntas. Suporta HTML.
vue
<template>
<MeUserFeedbackModal
:visible="isOpen"
title="Sua opinião importa!"
description="Sua resposta nos ajuda a <strong>melhorar continuamente</strong> a plataforma."
:questions="questions"
@submit="handleSubmit"
@close="isOpen = false"
/>
</template>API
Props
| Prop | Tipo | Padrão | Descrição |
|---|---|---|---|
visible | boolean | false | Controla a visibilidade do modal |
title | string | 'Sua opinião é muito importante para nós!' | Título do header |
description | string | '' | Texto descritivo acima das perguntas (suporta HTML) |
questions | FeedbackQuestion[] | [] | Lista de perguntas do formulário |
width | string | '600px' | Largura do modal |
bodyMaxHeight | string | '70vh' | Altura máxima do body — ativa scroll quando excedida |
submitLabel | string | 'Enviar' | Label do botão de confirmação |
cancelLabel | string | 'Cancelar' | Label do botão de cancelamento |
loading | boolean | false | Spinner no botão e desabilita envio |
answers | FeedbackAnswers | {} | Respostas controladas externamente (v-model:answers) |
Eventos
| Evento | Payload | Descrição |
|---|---|---|
submit | FeedbackAnswers | Emitido ao confirmar com todas as obrigatórias respondidas |
close | — | Emitido ao cancelar ou fechar o modal |
update:answers | FeedbackAnswers | Emitido a cada mudança de resposta — use com v-model:answers |
Tipos
FeedbackQuestion
| Campo | Tipo | Descrição |
|---|---|---|
key | string | Identificador único da pergunta (chave no objeto de respostas) |
label | string | Texto da pergunta |
type | 'range' | 'text' | 'textarea' | 'email' | Tipo de campo |
required | boolean? | Se verdadeiro, bloqueia o envio até ser respondido |
description | string? | Texto auxiliar abaixo do label |
placeholder | string? | Placeholder para campos text/textarea/email |
hint | string? | Texto de dica abaixo do campo email |
rows | number? | Número de linhas da textarea (padrão: 4) |
maxLength | number? | Limite de caracteres (text: 255, textarea: 500) |
min | number? | Valor mínimo do range (padrão: 1) |
max | number? | Valor máximo do range (padrão: 5) |
minLabel | string? | Label do extremo inferior do range (padrão: 'Insatisfeito') |
maxLabel | string? | Label do extremo superior do range (padrão: 'Satisfeito') |
showLabels | boolean? | Exibe os labels de min/max abaixo das estrelas (padrão: true) |
FeedbackAnswers
typescript
interface FeedbackAnswers {
[key: string]: number | string | null
}Acessibilidade
- Cada botão de estrela possui atributo
titlecom"N estrela(s)"para leitores de tela - Campos de texto e email usam labels visíveis com marcação de obrigatório (
*) - O botão Enviar é desabilitado nativamente até que os campos obrigatórios sejam preenchidos
Conteúdo HTML na descrição
A prop description renderiza HTML via v-html. Certifique-se de sanitizar o conteúdo antes de passá-lo ao componente para evitar XSS.