Criando componentes expandíveis com animações suaves
•6 min de leitura
Como implementar cards expandíveis com Framer Motion que mantêm o estilo existente mas adicionam interatividade elegante.
ReactAnimationFramer MotionUX
Criando componentes expandíveis com animações suaves#
Hoje vou mostrar como transformei cards estáticos em componentes interativos com expansão suave, mantendo o design original.
O Desafio#
Tinha cards de experiência simples e queria adicionar:
- Click para expandir detalhes
- Hover com ícone animado
- Manter o estilo existente
- Responsivo e acessível
Implementação#
1. Interface Flexível#
interface ExperienceCardProps {
title: string;
period: string;
description: string;
detailedDescription?: string; // Novo!
technologies?: string[]; // Novo!
logoUrl?: string; // Novo!
href?: string; // Novo!
}
2. Estado e Lógica#
const [isExpanded, setIsExpanded] = useState(false);
const handleClick = () => {
if (detailedDescription || technologies) {
setIsExpanded(!isExpanded);
}
};
const hasExpandableContent = detailedDescription || technologies;
3. Animação do Chevron#
<ChevronDownIcon
className={cn(
"w-4 h-4 opacity-0 -translate-x-2 transition-all duration-300",
"group-hover:opacity-50 group-hover:translate-x-0",
isExpanded && "rotate-180"
)}
/>
4. Conteúdo Expandível#
<motion.div
initial={{ opacity: 0, height: 0 }}
animate={{
opacity: isExpanded ? 1 : 0,
height: isExpanded ? "auto" : 0,
}}
transition={{
duration: 0.4,
ease: [0.16, 1, 0.3, 1], // Custom easing
}}
className="overflow-hidden"
>
<div className="pt-3 space-y-3">
{detailedDescription && (
<p className="text-sm opacity-60 leading-relaxed">
{detailedDescription}
</p>
)}
{technologies && (
<div className="flex flex-wrap gap-1">
{technologies.map((tech, index) => (
<span
key={index}
className="px-2 py-1 bg-neutral-100 dark:bg-neutral-800 rounded text-xs"
>
{tech}
</span>
))}
</div>
)}
</div>
</motion.div>
Resultado#
O componente agora oferece:
- Progressão visual clara - Usuário entende que pode interagir
- Feedback imediato - Hover mostra o ícone
- Animação natural - Expansão suave sem "jumps"
- Compatibilidade - Funciona com designs existentes
Dicas de UX#
- Sempre sinalize interatividade - Cursor pointer + hover states
- Animate height: auto cuidadosamente - Use motion.div adequadamente
- Mantenha consistência - Mesmo estilo, nova funcionalidade
- Teste em mobile - Touch targets adequados
A diferença entre um bom componente e um excelente está nos detalhes de interação!