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#

  1. Sempre sinalize interatividade - Cursor pointer + hover states
  2. Animate height: auto cuidadosamente - Use motion.div adequadamente
  3. Mantenha consistência - Mesmo estilo, nova funcionalidade
  4. Teste em mobile - Touch targets adequados

A diferença entre um bom componente e um excelente está nos detalhes de interação!