Retour au catalogue

Careers Values First

Page carrieres mettant les valeurs d'entreprise en avant avant les offres d'emploi.

careersmedium Both Responsive a11y
elegantcorporatesaasuniversalagencystackedgrid
Theme

Cómo crear una sección de empleo centrada en los valores en React

Una sección de empleo centrada en los valores en React muestra los valores de la empresa en una cuadrícula de tarjetas de 2 columnas antes de listar los puestos abiertos. Cada tarjeta aparece con una animación translate-Y escalonada mediante whileInView de Framer Motion, y una barra CTA con fondo de acento cierra la sección.

  • Stack: React + Framer Motion 11 + Lucide React, ~93 líneas, cero dependencias adicionales.
  • Animación: stagger activado por viewport, cada tarjeta se retrasa 0.06s × índice mediante whileInView con once:true.
  • Los iconos se resuelven en tiempo de ejecución desde un record ICON_MAP (Shield, Zap, Heart, BookOpen de Lucide).
  • Accesible: encabezados h2/h3 semánticos, contraste de color delegado a los tokens CSS, ningún significado transmitido solo por la animación.
  • Responsive: la cuadrícula de 2 columnas se mantiene en todos los anchos; se ajusta de forma natural en pantallas estrechas mediante CSS grid.

CareersValuesFirst abre una página de empleo con aquello que defiende la empresa antes de mostrar los puestos. Un bloque de titular corto precede a una cuadrícula de tarjetas de 2 columnas donde cada valor recibe un icono, un título y una descripción. Una barra de acento a todo lo ancho en la parte inferior conecta la sección con un CTA de ofertas de empleo, ofreciendo a los reclutadores un argumento de cultura y una acción de conversión en el mismo scroll.

Anatomía

La sección tiene tres partes apiladas verticalmente. Primero, un bloque de cabecera (max-width 640px) con un h2 y un párrafo de subtítulo, revelado como una sola unidad. Segundo, una cuadrícula CSS con 2 columnas iguales y un espacio de 1.5rem; cada tarjeta tiene padding, un borde redondeado, un fondo card y un círculo decorativo difuminado en la esquina superior derecha al 5% de opacidad. Dentro de cada tarjeta: un contenedor de icono de 48×48px con fondo accent-subtle, luego un título h3, luego un párrafo muted. Tercero, una flex row con fondo de acento que contiene el número de puestos abiertos a la izquierda y un enlace CTA en forma de píldora a la derecha.

Cómo funciona

Cada elemento animado usa whileInView de Framer Motion con viewport={{ once: true }} para que la animación se dispare una sola vez cuando el elemento entra en pantalla y nunca se repita al subir el scroll. La cabecera se anima como un solo bloque (opacity 0→1, y 20→0, duración 0.6s). Cada tarjeta de valor se retrasa `0.08 + i * 0.06` segundos, creando un stagger natural de izquierda a derecha a lo largo de las columnas de la cuadrícula. La barra CTA espera 0.3s, entrando después de la última tarjeta. Todas las transiciones comparten el mismo ease personalizado `[0.16, 1, 0.3, 1]`, un ease-out rápido que se percibe ágil en lugar de rebotante.

Cómo crearlo en React

  1. Definir la interfaz Value y el mapa de iconos

    Cada objeto value lleva una clave icon (string), un título, una descripción y un hex de color usado para el blob decorativo del fondo. Resuelve las cadenas de iconos a componentes Lucide reales en la parte superior del archivo con un lookup Record para que la API de props siga siendo serializable.

    const ICON_MAP: Record<string, LucideIcon> = {
      shield: Shield,
      zap: Zap,
      heart: Heart,
      "book-open": BookOpen,
    };
  2. Animar la cabecera como un solo bloque

    Envuelve el h2 + subtítulo en un único motion.div con initial={{ opacity: 0, y: 20 }} y whileInView={{ opacity: 1, y: 0 }}. Pon viewport={{ once: true }} para evitar repeticiones. Una duración de 0.6s con el ease personalizado basta, aquí no hace falta stagger, el bloque es pequeño.

    <motion.div
      initial={{ opacity: 0, y: 20 }}
      whileInView={{ opacity: 1, y: 0 }}
      viewport={{ once: true }}
      transition={{ duration: 0.6, ease: [0.16, 1, 0.3, 1] }}
    >
  3. Escalonar las tarjetas de valores

    Recorre el array de valores y da a cada motion.div un delay de `0.08 + i * 0.06`. Con 4 tarjetas esto reparte la entrada en ~0.3s en total, lo que se percibe fluido sin parecer lento. El blob decorativo es un div de 100px con borderRadius 50%, posicionado en absoluto en top:-20 right:-20, usando el color del valor al 5% de opacidad.

    transition={{ duration: 0.5, delay: 0.08 + i * 0.06, ease: EASE }}
  4. Construir la barra CTA de acento

    Renderiza un motion.div con display:flex, el fondo de acento y un delay de 0.3s para que entre el último. Dentro, una flex row contiene un bloque de texto a la izquierda (número de puestos + tagline) y un enlace píldora a la derecha con el color de fondo como su propio fondo, creando un botón invertido a partir del acento de la sección.

    <motion.div
      initial={{ opacity: 0, y: 12 }}
      whileInView={{ opacity: 1, y: 0 }}
      viewport={{ once: true }}
      transition={{ duration: 0.5, delay: 0.3, ease: EASE }}
      style={{ background: "var(--color-accent)" }}
    >

Cuándo usarlo

Usa esta sección al principio de una página de empleo o de información cuando la cultura es un diferenciador, empresas SaaS, agencias y startups que compiten por talento según los valores en lugar del salario. Colócala antes de la lista de ofertas para que los visitantes lean el porqué antes del qué. Evítala en los job boards transaccionales o en páginas donde el tiempo hasta postularse es la prioridad; en esos contextos la profundidad de scroll adicional cuesta conversiones.

Usado por

  • Stripe, Abre su página de empleo con sus principios de funcionamiento antes de listar los puestos, estableciendo la cultura antes que la oportunidad.
  • Linear, La sección de valores y forma de trabajar precede al tablón de ofertas, poniendo el énfasis en cómo funciona el equipo más que en cuáles son los puestos.
  • Notion, Muestra los valores fundamentales con iconos y descripciones cortas encima de la lista de puestos abiertos en su página de empleo.

FAQ

¿Cómo añado una quinta tarjeta de valor sin romper la cuadrícula de 2 columnas?

La cuadrícula usa `repeat(2, 1fr)` así que cualquier número de tarjetas la rellena automáticamente, una quinta tarjeta simplemente inicia una nueva fila. Si la quieres centrada en la última fila, envuelve el contenedor de la cuadrícula en un padre flex y añade `justify-items: center`.

¿Puedo añadir un icono personalizado que no esté en el ICON_MAP?

Amplía el record ICON_MAP con cualquier icono Lucide o tu propio componente SVG, el tipo es `Record<string, LucideIcon>`, así que cualquier componente que acepte una prop className o style funciona. El fallback es Shield si no se encuentra la clave.

¿whileInView se reproduce cada vez que el elemento vuelve a entrar en el viewport?

No con `viewport={{ once: true }}`, que es lo que usa este componente. La animación se dispara una sola vez en la primera intersección y nunca más. Elimina el flag once para que se reproduzca en cada entrada al hacer scroll hacia abajo.

¿Cómo conecto el enlace CTA a un ancla real de la página de ofertas?

Reemplaza `href="#"` en la etiqueta anchor por `href="#jobs"` (o el id que des a tu sección de listados). Pasa `ctaText` y `openPositionsCount` como props desde tu fuente de datos para que la barra refleje el número real de vacantes.

"use client";

import { motion } from "framer-motion";
import { Shield, Zap, Heart, BookOpen, ArrowRight } from "lucide-react";
import type { LucideIcon } from "lucide-react";

interface Value {
  icon: string;
  title: string;
  description: string;
  color: string;
}

interface CareersValuesFirstProps {
  title?: string;
  subtitle?: string;
  values?: Value[];
  ctaText?: string;
  openPositionsCount?: number;
}

const EASE = [0.16, 1, 0.3, 1] as const;

Code complet réservé à Pro

Code source intégral, export multi-framework et playground.

Passer en Pro, 9,99€/mois

Reseñas

Sección de valores React para página de empleo, cuadrícula +