Manipulación de SVG con Claude Code: guía práctica
Aprende a usar Claude Code con SVG: viewBox, iconos accesibles, currentColor, animaciones, SVGO y errores de seguridad comunes.
Antes de pedirle un SVG a Claude Code
SVG sirve para iconos, logotipos, diagramas y pequeñas visualizaciones porque no pierde nitidez al escalar y puede heredar estilos de CSS. Claude Code puede leer el repositorio, editar archivos y ejecutar comprobaciones, así que encaja bien cuando quieres convertir SVG sueltos en componentes mantenibles.
El problema aparece cuando el prompt es demasiado corto. “Crea un icono SVG” puede producir algo visualmente correcto, pero sin viewBox, con colores fijos, sin nombre accesible o con una optimización que rompe el escalado. A Masa le pasó en una prueba de UI para ClaudeCodeLab: el icono se veía bien, pero había que retocarlo cada vez que se usaba en un botón con texto, en un botón solo con icono y en modo oscuro.
Esta guía propone un flujo más seguro: fijar viewBox, usar currentColor, separar iconos decorativos de iconos con significado, añadir animación ligera sin molestar y optimizar con SVGO sin borrar atributos importantes. Las referencias oficiales son MDN <svg>, MDN viewBox, MDN ARIA img role, MDN aria-hidden, SVGO y la documentación de Claude Code.
Flujo recomendado
Trabajar con SVG no es solo dibujar. En una aplicación real afecta al sistema de diseño, la accesibilidad, el rendimiento y la seguridad.
flowchart LR
A["Definir el objetivo"] --> B["Fijar viewBox"]
B --> C["Usar currentColor"]
C --> D["Elegir aria-label o aria-hidden"]
D --> E["Integrar en HTML o React"]
E --> F["Optimizar con SVGO"]
F --> G["Revisar diseño y seguridad"]
Un prompt útil sería: “Crea un componente de iconos SVG con viewBox="0 0 24 24", stroke="currentColor", iconos decorativos con aria-hidden, iconos independientes con role="img" y title, y una configuración de SVGO que conserve viewBox”.
Inline SVG y viewBox
Inline SVG significa escribir el marcado <svg> dentro de HTML o JSX, en lugar de cargar un archivo con img. Es la opción adecuada cuando el icono debe cambiar de color, reaccionar a hover, integrarse con React o animarse de forma ligera.
viewBox define el sistema de coordenadas interno. MDN lo describe como cuatro números: min-x min-y width height. En términos simples, viewBox="0 0 24 24" indica que el dibujo vive en una cuadrícula de 24 por 24 unidades, aunque se muestre a 16px, 24px o 48px.
<button class="icon-button" type="button" aria-label="Buscar">
<svg
class="icon"
viewBox="0 0 24 24"
width="24"
height="24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
focusable="false"
>
<circle cx="11" cy="11" r="7" />
<path d="M20 20l-4.5-4.5" />
</svg>
</button>
El botón ya tiene el nombre accesible, por eso el SVG se marca como decorativo. Si el icono fuera el único contenido visible del botón, el nombre debe estar en el botón. Si el SVG se muestra como imagen con significado propio, entonces el SVG necesita un nombre.
Temas con currentColor y variables CSS
Los colores fijos dentro del SVG dificultan el mantenimiento. Si una ruta tiene fill="#111827", Claude Code tendrá que tocar el SVG cada vez que cambie el tema. Es mejor que el SVG herede el color desde CSS.
:root {
--color-text: #172033;
--color-muted: #667085;
--color-accent: #0f766e;
--color-danger: #b42318;
}
[data-theme="dark"] {
--color-text: #eef2f7;
--color-muted: #a9b4c3;
--color-accent: #2dd4bf;
--color-danger: #f97066;
}
.icon {
color: var(--icon-color, var(--color-text));
display: inline-block;
inline-size: 1.25rem;
block-size: 1.25rem;
flex: 0 0 auto;
}
.icon-button {
color: var(--color-muted);
}
.icon-button:hover {
color: var(--color-accent);
}
.icon-button[data-variant="danger"] {
--icon-color: var(--color-danger);
}
<button class="icon-button" type="button" aria-label="Eliminar" data-variant="danger">
<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" aria-hidden="true">
<path d="M4 7h16" />
<path d="M10 11v6" />
<path d="M14 11v6" />
<path d="M6 7l1 14h10l1-14" />
<path d="M9 7V4h6v3" />
</svg>
</button>
Después del cambio, pide a Claude Code que busque colores fijos con rg "fill=\"#|stroke=\"#" en los componentes y assets. Los logotipos pueden ser una excepción, pero los iconos de UI deberían heredar color.
Componente React accesible
Un SVG con significado necesita un nombre accesible. Un SVG decorativo debe ocultarse del árbol de accesibilidad. MDN recomienda role="img" y una etiqueta para SVG incrustados que actúan como imagen, y aria-hidden="true" para contenido decorativo no interactivo.
import { useId } from "react";
type IconName = "search" | "check" | "close";
const paths: Record<IconName, string> = {
search: "M10.5 18a7.5 7.5 0 1 1 5.3-12.8 7.5 7.5 0 0 1-5.3 12.8Zm5.3-2.2L21 21",
check: "M5 12.5l4.5 4.5L19 7",
close: "M6 6l12 12M18 6L6 18",
};
type SvgIconProps = {
name: IconName;
title?: string;
decorative?: boolean;
size?: number;
className?: string;
};
export function SvgIcon({
name,
title,
decorative = false,
size = 24,
className,
}: SvgIconProps) {
const titleId = useId();
const isMeaningful = !decorative && Boolean(title);
return (
<svg
className={className}
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
role={isMeaningful ? "img" : undefined}
aria-labelledby={isMeaningful ? titleId : undefined}
aria-hidden={decorative ? true : undefined}
focusable="false"
>
{isMeaningful ? <title id={titleId}>{title}</title> : null}
<path d={paths[name]} />
</svg>
);
}
<button type="button">
<SvgIcon name="check" decorative />
Guardar
</button>
<SvgIcon name="search" title="Buscar" />
No pongas aria-hidden="true" en elementos que pueden recibir foco. Si un botón solo tiene icono, etiqueta el botón o añade texto visible.
Animación ligera
La animación SVG funciona bien para carga, confirmación y pequeños énfasis. Mantén dimensiones estables y respeta prefers-reduced-motion.
<svg class="spinner" viewBox="0 0 48 48" width="48" height="48" role="img" aria-label="Cargando">
<circle class="spinner-track" cx="24" cy="24" r="20" />
<circle class="spinner-head" cx="24" cy="24" r="20" />
</svg>
.spinner {
color: #0f766e;
animation: spin 900ms linear infinite;
}
.spinner-track,
.spinner-head {
fill: none;
stroke-width: 4;
}
.spinner-track {
stroke: #d0d5dd;
}
.spinner-head {
stroke: currentColor;
stroke-linecap: round;
stroke-dasharray: 80 45;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
@media (prefers-reduced-motion: reduce) {
.spinner {
animation: none;
}
}
Para patrones de movimiento más amplios, conecta este tema con animaciones CSS avanzadas con Claude Code. SVG debería describir la forma; CSS debería describir el estado y el movimiento.
SVG para pequeños gráficos
SVG también sirve para gráficos simples. Si una etiqueta viene de datos externos, escápala antes de insertarla en <text>.
type BarDatum = {
label: string;
value: number;
};
function escapeXml(value: string): string {
return value.replace(/[<>&"']/g, (char) => {
const entities: Record<string, string> = {
"<": "<",
">": ">",
"&": "&",
'"': """,
"'": "'",
};
return entities[char];
});
}
export function createMiniBarChart(data: BarDatum[]): string {
const width = 420;
const height = 180;
const padding = 32;
const gap = 12;
const maxValue = Math.max(...data.map((item) => item.value), 1);
const barWidth = (width - padding * 2 - gap * (data.length - 1)) / data.length;
const bars = data
.map((item, index) => {
const barHeight = (item.value / maxValue) * 100;
const x = padding + index * (barWidth + gap);
const y = height - padding - barHeight;
return `
<rect x="${x}" y="${y}" width="${barWidth}" height="${barHeight}" rx="6" fill="currentColor" />
<text x="${x + barWidth / 2}" y="${height - 10}" text-anchor="middle" font-size="12">
${escapeXml(item.label)}
</text>`;
})
.join("");
return `<svg viewBox="0 0 ${width} ${height}" role="img" aria-label="Consultas mensuales" xmlns="http://www.w3.org/2000/svg">
<g color="#0f766e">${bars}</g>
</svg>`;
}
Este enfoque sirve para dashboards pequeños, ilustraciones de artículos y pruebas sociales en una landing page. Usa una librería de gráficos cuando necesites ejes, leyendas, tooltips, zoom o muchos datos.
Optimización con SVGO
Los SVG exportados desde herramientas de diseño suelen traer metadatos, atributos de editor y precisión innecesaria. SVGO limpia ese ruido. Empieza con una configuración conservadora y revisa el diff.
// svgo.config.mjs
export default {
multipass: true,
plugins: [
{
name: "preset-default",
params: {
overrides: {
cleanupIds: false
}
}
},
"removeDimensions",
{
name: "removeAttrs",
params: {
attrs: ["data-name"]
}
}
]
};
{
"scripts": {
"svg:optimize": "svgo --config svgo.config.mjs --folder src/assets/icons"
},
"devDependencies": {
"svgo": "^4.0.0"
}
}
SVGO documenta preset-default, removeDimensions y otros plugins. Ten cuidado con removeViewBox: la documentación advierte que puede impedir que el SVG escale y puede provocar recortes.
Casos de uso y errores
Casos habituales: un sistema de iconos de producto; diagramas para artículos técnicos; visuales cerca de precios, checklists y botones de compra; pequeños gráficos de lectura, clics en CTA o volumen de consultas.
| Error | Resultado | Solución |
|---|---|---|
Quitar viewBox | El icono se recorta o no escala | Conservarlo en SVGO y revisar diff |
| Colores fijos | Fallan dark mode y hover | Usar currentColor |
| Ocultar iconos con significado | El lector de pantalla pierde contexto | Nombrar el botón o el SVG |
| Leer iconos decorativos | Nombres duplicados y ruido | Usar aria-hidden="true" |
| Insertar SVG subido por usuarios | Riesgo de scripts o eventos | Inline solo para SVG confiables |
| Ignorar movimiento reducido | Puede molestar a usuarios sensibles | Usar prefers-reduced-motion |
MDN documenta el elemento SVG <script>, así que no trates un SVG subido como si fuera texto inocuo. Claude Code ayuda a revisar diferencias, pero limita siempre la carpeta objetivo y revisa los cambios. Para permisos y ejecución de comandos, consulta también la página de seguridad de Claude Code.
Prompt reutilizable
Crea un sistema de iconos SVG para este repositorio.
Requisitos:
- Mantener viewBox="0 0 24 24"
- Usar currentColor en fill o stroke
- Ocultar iconos decorativos con aria-hidden=true
- Usar role=img y title en iconos independientes con significado
- Añadir un SVG de carga compatible con prefers-reduced-motion
- Añadir una configuración de SVGO que no elimine viewBox
- Reportar riesgos, archivos modificados y comandos de verificación
Para ampliar la parte de rendimiento, continúa con optimización de rendimiento con Claude Code.
CTA y resultado probado
Si quieres convertir esto en una configuración reutilizable, revisa los productos y plantillas de ClaudeCodeLab o lleva tu repositorio real a una sesión de formación y consultoría de Claude Code. SVG es un buen primer caso porque toca diseño, accesibilidad, rendimiento y revisión de cambios en un alcance pequeño.
En la prueba de Masa, mover colores fijos a currentColor permitió usar los mismos iconos en modo claro, modo oscuro y botones destructivos. El error real apareció en accesibilidad: un botón de búsqueda solo con icono perdió su nombre cuando se aplicó aria-hidden de forma mecánica. La regla final fue etiquetar el botón y ocultar solo iconos decorativos.
PDF gratis: cheatsheet de Claude Code
Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.
Cuidamos tus datos y no enviamos spam.
Sobre el autor
Masa
Ingeniero enfocado en workflows prácticos con Claude Code.
Artículos relacionados
Escalera de permisos de Claude Code para ampliar acceso sin perder control
Pasa de read-only a ediciones limitadas, comandos de prueba y checks de deploy con menos riesgo.
Claude Code Small PR Proof Pack: cambios pequeños que sí se pueden revisar
Un paquete de prueba para PRs de Claude Code: diff, checks, URL pública, CTA y rollback.
Gate de revisión antes del commit con Claude Code
Cómo revisar con Claude Code antes del commit: diff, build, URL pública, Gumroad, consultoría, tests y archivos ajenos.