Componentes React personalizados
Define y usa componentes React personalizados en MDX con renderizado en servidor, estilos Tailwind y componentes integrados de Jamdesk.
Define componentes React personalizados directamente en archivos MDX. Exporta un componente de función flecha en la parte superior del archivo y úsalo en línea. Los componentes se renderizan en el servidor en tiempo de build, con acceso a todos los componentes integrados de Jamdesk y a las clases de Tailwind.
Uso básico
Define un componente usando export const en la parte superior de tu archivo MDX:
export const Highlight = ({ children, color }) => (
<span style={{ backgroundColor: color, padding: '0.2em 0.4em', borderRadius: '4px' }}>
{children}
</span>
);
This text has a <Highlight color="#ffeb3b">yellow highlight</Highlight> in it.
Los nombres de los componentes deben usar PascalCase (empezar con una letra mayúscula).
Ejemplo: tarjeta hero
Aquí tienes un ejemplo más complejo con múltiples props y clases de Tailwind:
export const HeroCard = ({ title, description, href, icon }) => (
<a
href={href}
className="group block p-6 rounded-lg border border-gray-200 hover:border-blue-500 transition-colors"
>
<div className="flex items-center gap-3 mb-2">
<Icon icon={icon} />
<h3 className="font-semibold text-lg">{title}</h3>
</div>
<p className="text-gray-600">{description}</p>
</a>
);
<div className="grid grid-cols-2 gap-4">
<HeroCard
title="Getting started"
description="Learn the basics"
href="/quickstart"
icon="rocket"
/>
<HeroCard
title="Components"
description="Explore available components"
href="/components/overview"
icon="puzzle-piece"
/>
</div>
Uso de componentes integrados
Tus componentes personalizados tienen acceso a todos los componentes integrados de Jamdesk. No se necesitan imports:
export const FeatureCard = ({ title, children }) => (
<Card title={title} icon="star">
{children}
<Tip>This tip is inside a custom component!</Tip>
</Card>
);
<FeatureCard title="My Feature">
<Note>Notes work inside custom components too!</Note>
</FeatureCard>
Componentes integrados por categoría:
| Categoría | Componentes |
|---|---|
| Avisos | Note, Tip, Info, Warning, Check, Danger |
| Diseño | Card, Columns, Tabs, Tab, Accordion, Steps, Step, View |
| Medios | Frame, Icon, Badge, Tooltip |
| Código | CodeGroup |
| Documentación de API | ParamField, ResponseField, Expandable |
Limitaciones
- Solo funciones flecha: usa la sintaxis
export const. La sintaxisexport functionno es compatible. - Sin imports: no puedes importar paquetes externos ni otros archivos
- Sin hooks: los hooks de React (
useState,useEffect,useRef, etc.) no están disponibles. Los componentes se renderizan en el servidor durante el build, y los hooks solo funcionan en el cliente. Para componentes interactivos, usa archivos snippet en su lugar (consulta la solución de problemas más abajo). - Solo del lado del servidor: los componentes se renderizan en el servidor; no hay interactividad del lado del cliente ni controladores de eventos
- Solo Tailwind: usa clases de Tailwind CSS para los estilos; CSS-in-JS no está disponible
- Sintaxis estricta: los errores de sintaxis en componentes inline harán fallar el build con un mensaje de error claro
- Nombres en PascalCase: los nombres de los componentes deben empezar con una letra mayúscula y contener solo letras y números (sin guiones bajos)
¿Necesitas hooks de React? Los componentes inline no pueden usar useState, useEffect ni otros hooks porque se renderizan en el servidor durante el build. Para componentes interactivos que necesiten estado o efectos, crea un archivo snippet con la directiva 'use client' (consulta la sección de solución de problemas más abajo).
Buenas prácticas
Los componentes inline deben ser presentacionales. Para lógica compleja, solicita un componente integrado.
Asegúrate de que tus componentes sean accesibles, con elementos HTML adecuados y atributos ARIA.
Previsualiza tu documentación localmente para verificar que los componentes se renderizan correctamente tanto en modo claro como en modo oscuro.
Solución de problemas
Error: Expected component 'MyComponent' to be defined
Causas:
- El nombre del componente no usa PascalCase (debe empezar con una letra mayúscula)
- Error de sintaxis en la definición del componente
- Falta la etiqueta de cierre o el paréntesis
Solución: Verifica que tu export siga este patrón:
export const MyComponent = ({ prop }) => (
<div>{prop}</div>
);Error: El build falla mencionando Babel o sintaxis JSX
Causas:
- Sintaxis JSX inválida en tu componente
- Etiquetas o llaves sin cerrar
- Uso de funciones de JavaScript no compatibles
Solución: Verifica que tu JSX sea válido. Problemas comunes:
- Todas las etiquetas deben cerrarse (
<img loading="lazy" />en vez de<img loading="lazy">) - Usa
classNameen lugar declass - Envuelve varios elementos en un fragmento
<>...</>o en un elemento padre
Advertencia: Inline component(s) override built-in: Note
Causa: Tu componente inline tiene el mismo nombre que un componente integrado.
Solución: Cambia el nombre de tu componente para evitar conflictos:
// Instead of: export const Note = ...
export const CustomNote = ({ children }) => (
<div className="my-note">{children}</div>
);Problema: Las clases de Tailwind no funcionan
Causas:
- Uso de CSS-in-JS u objetos de estilo inline (soporte limitado)
- La clase de Tailwind no está incluida en el build
Solución: Usa las clases de utilidad estándar de Tailwind. Para estilos personalizados, usa la prop style inline con valores simples:
export const Highlight = ({ children }) => (
<span style={{ backgroundColor: '#ffeb3b' }}>{children}</span>
);Problema: El componente definido con export function no se renderiza
Causa: Solo se admite la sintaxis de función flecha con export const.
Solución: Convierte tu función a sintaxis de función flecha:
// Instead of:
export function MyComponent({ prop }) {
return <div>{prop}</div>;
}
// Use:
export const MyComponent = ({ prop }) => (
<div>{prop}</div>
);Problema: Un componente con guiones bajos o caracteres especiales no funciona
Causa: Los nombres de los componentes deben ser identificadores PascalCase válidos (solo letras y números).
Solución: Usa solo letras y números en el nombre de tu componente:
// Instead of: export const Hero_Card = ...
// Instead of: export const my-component = ...
export const HeroCard = ({ title }) => (
<div>{title}</div>
);Error: ReferenceError: useState is not defined
Causa: Los hooks de React no están disponibles en los componentes inline. Los componentes inline se renderizan en el servidor durante el proceso de build, y los hooks solo funcionan en componentes React del lado del cliente.
Solución: Para componentes interactivos que necesiten estado o efectos, crea un archivo snippet en su lugar:
- Crea un archivo en tu directorio
/snippets(por ejemplo,/snippets/counter.tsx) - Agrega
'use client'al principio del archivo - Impórtalo y úsalo en tu MDX
'use client';
import { useState } from 'react';
export function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(c => c + 1)}>
Count: {count}
</button>
);
}import { Counter } from '/snippets/counter';
<Counter />