HTML SVG
html svg svg is the production choice for icons, logos, and moderate data viz when access inline svg is vector
Introduction
Inline SVG is vector markup in the DOM — every <path> is a node with geometry, style, and event targets. Staff engineers prefer SVG for icons and data viz under ~500 interactive elements because it scales crisply at any DPR, participates in the accessibility tree (with correct roles), and compresses well in sprite systems like GitHub's Octicons and Google's Material Symbols pipeline.
Business problem
Business pressure: Design systems ship thousands of icons across Airbnb, Google, and Shopify surfaces. Raster sprites blur on retina; icon fonts fail WCAG and FOIT. Inline SVG in HTML — or external sprites with <use href="#id"> — is the enterprise default, but bloated path data from design exports can inflate HTML TTFB and parser cost.
- Conversion: Broken or missing icons on checkout erode trust — SVG must degrade to text labels, not empty boxes.
- Compliance: Decorative SVG needs
aria-hidden="true"; informative icons need<title>oraria-label— lawsuit targets include missing form field icons. - SEO: SVG text nodes are indexable; logo SVGs with embedded company names beat canvas logos for brand queries.
Why this feature exists
Platform motivation: SVG predates HTML5 canvas as an W3C vector format. Browsers integrated it into HTML parsing so authors could embed scalable graphics without Flash. When Apple banned Flash on iOS, SVG + CSS animation replaced swf banners on major publishers.
- History: SVG 1.1 (2003); HTML5 allows inline SVG without XML prolog — parser switches to foreign content namespace.
- Alternative rejected: PNG @2x/@3x asset matrices explode CMS storage and CDN invalidation complexity.
- Modern role: Icons, maps (Mapbox GL outputs canvas; static map pins often SVG), charts (D3), animated loaders — complements canvas for retained graphics.
Browser internals
Inside the engine: The HTML parser enters SVG "foreign content" adjustment when it sees <svg>. Elements become SVG DOM nodes (SVGPathElement, etc.) mixed in the HTML document. Style calculation applies SVG presentation attributes + CSS; layout uses SVG viewport and viewBox mapping — not always the CSS box model for inner coordinates.
- Parser: Tag names and attributes are case-sensitive in foreign content; self-closing rules differ from HTML.
- DOM: Each shape is a node — 500 paths = 500 layout/style objects; memory scales with complexity.
- Script impact:
getBBox()andgetTotalLength()force geometry recalc — batch after DOM inserts.
<!-- Parser builds mixed tree --><div class="card"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2L2 7v10l10 5 10-5V7z"/></svg><span>Shipped</span></div>// DevTools: path is SVGPathElement, participates in hit-testing
Rendering workflow
Rendering path: SVG generates a render object subtree. Simple fills are rasterized at display resolution; complex filters (<feGaussianBlur>) trigger offscreen passes. CSS transforms on <svg> promote compositor layers — Airbnb map pin bounce animations use transform, not top/left, to avoid layout.
- Critical path: Inline hero SVG in HTML adds to document weight — external sprite +
<use>caches across pages. - Layout: Missing
width/heightorviewBoxcauses intrinsic size 300×150 default — classic CLS on icon-only buttons. - Paint: Long dashed strokes and filters are paint-heavy — simplify paths exported from Figma (SVGO in CI).
Feature deep dive
SVG production model: Retained-mode vector graphics in DOM. Use viewBox for responsive scaling, <symbol> + <use> for sprites, CSS currentColor for themeable icons — GitHub's pattern for light/dark mode without duplicate assets.
- Shapes:
<rect>,<circle>,<path d="...">— paths are most compact for icons. - Accessibility:
<title>first child for SR; decorative iconsaria-hidden="true" focusable="false". - Animation: CSS
@keyframesontransformor SMIL (deprecated — avoid for new work).
<svg class="icon" viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" focusable="false"><path fill="currentColor" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15v-4H8l4-4 4 4h-3v4h-2z"/></svg><!-- Informative --><svg role="img" aria-labelledby="status-title" viewBox="0 0 24 24" width="24" height="24"><title id="status-title">Order shipped</title><circle cx="12" cy="12" r="10" fill="#22c55e"/></svg>
Accessibility analysis
A11y architecture: SVG can expose name via <title>, aria-label, or aria-labelledby. Role img maps to graphic on accessibility tree. Interactive SVG buttons need role="button", tabindex, and keyboard handlers — Google Maps custom controls pattern.
- Screen readers: IE legacy required
focusable="false"on decorative SVG — still best practice for Firefox SVG focus quirks. - Keyboard: Clickable paths need visible focus — outline on
<a>wrapper preferred over raw path click targets. - WCAG: 1.4.11 Non-text Contrast — icon strokes must meet 3:1 against adjacent colors, not just brand palette approval.
SEO impact
SEO architecture: Text inside <svg><text> is crawlable. Logo markup with company name aids brand SERP. Over-large inline SVG in <body> above fold increases HTML bytes — hurts TTFB and parser time; Google Search Console HTML size alerts are common on icon-heavy SPAs.
- Crawl: Prefer external SVG for decorative complexity; keep critical textual content in HTML headings.
- Rich results: Organization logo structured data should reference PNG/JPG URL — many validators reject inline SVG URLs.
- Core Web Vitals: 200KB inline SVG sprite in HTML delays FCP — use cached external resource or HTTP/2 push sparingly.
Security considerations
Security boundary: SVG is XML — can embed <script>, onload, and foreignObject with HTML. User-uploaded SVG avatars are XSS vectors — Slack and GitHub sanitize with allowlists. Never serve raw user SVG with Content-Type: image/svg+xml inline in DOM without DOMPurify.
- XSS:
<svg><script>alert(1)</script>executes if injected via innerHTML — sanitize in CMS pipelines. - CSP: Restrict inline script; SVG use elements fetching external fragments need
script-srcand URL policy review. - Clickjacking: Full-screen transparent SVG hit regions over iframe embeds — audit z-index in ad slots.
Performance impact
Performance: SVG scales O(nodes) for DOM and style recalc. D3 charts with 5k circles lag INP — canvas or WebGL for that scale. SVGO in CI (Shopify theme pipeline) typically cuts path data 30–60%.
- LCP: Large inline SVG logo competes with hero image bytes — use compact path or PNG WebP for LCP logo if >10KB.
- INP: Hover handlers on hundreds of SVG map regions need event delegation on parent
<g>, not per-path listeners. - CLS: Always set explicit width/height or aspect-ratio on
<svg>container.
Real production example
GitHub Octicons pattern: Icons ship as optimized SVG strings in React components; currentColor inherits text color; decorative by default with opt-in aria-label prop. Sprite sheet alternative for static sites: one cached icons.svg + <svg><use href="/icons.svg#check"></use></svg>.
- SVGO config: Remove metadata, merge paths, precision 2 — run on every design handoff PR.
- Theme: CSS variables on
stroke/fill— no duplicate dark mode files. - Testing: Visual regression per icon size 16/20/24px — subpixel blur catches missing pixel-alignment.
<!-- Airbnb-style map pin — semantic wrapper --><button type="button" class="map-pin" aria-label="View listing, $120 per night"><svg viewBox="0 0 32 42" width="32" height="42" aria-hidden="true"><path fill="#ff385c" d="M16 0C7.2 0 0 7.2 0 16c0 11 16 26 16 26s16-15 16-26C32 7.2 24.8 0 16 0z"/><circle cx="16" cy="16" r="6" fill="#fff"/></svg></button>
Enterprise usage
Enterprise: Design tokens packages export SVG React/Vue components; CMS blocks reference icon ID, not raw path. Regulated industries block user SVG upload entirely — PDF-to-SVG conversion disabled in banking portals.
- Design system: Icon lint: max 1KB gzipped per glyph, mandatory viewBox, no embedded fonts.
- CMS: Sanitize SVG with allowlist tags: svg, path, circle, rect, g, title — strip script and foreignObject.
- CI gates: svgo + custom rule rejecting
<script>in staged SVG assets.
Common production failures
What breaks in prod: SVG failures are usually export bloat, XSS in uploads, or a11y omissions — not invalid path syntax.
- Incident: Marketing uploaded 800KB Illustrator SVG inline — mobile FCP +2.4s, rollback after RUM alert.
- SEO regression: N/A for icons, but replaced
<img alt="Company">logo with untitled SVG — brand accessibility complaints. - Security: Profile photo SVG with embedded script — XSS in admin panel; fix: sanitize + CSP + serve raster fallback.
Architecture review questions
- Is each icon decorative (aria-hidden) or named (title/aria-label)?
- Did SVGO run — any path over 1KB?
- Are width/height or aspect-ratio set to prevent CLS?
- Could user-supplied SVG reach the DOM unsanitized?
- Does stroke/fill meet non-text contrast on all themes?
- At what node count would you migrate this chart to canvas?
Hands-on project
Project: Build a design-system icon component: SVGO-optimized path, currentColor, decorative/informative modes, sprite fallback, axe verification.
- Deliverable: 10 icons with consistent viewBox, React/HTML variants, dark mode via CSS only.
- Verify: Total sprite <15KB; axe passes; no focus trap on decorative icons.
- Stretch: Document XSS test cases for rejected SVG uploads.
Interview questions
SVG sprite vs inline SVG vs icon font — production trade-offs?(Advanced)
Icon fonts: one request but FOIT, poor a11y, blurry subpixel. Inline: best styling, worst cache duplication. External sprite + use: best cache, HTTP/2 multiplex; watch CSP and cross-origin fragment IDs. GitHub inlines in components for tree-shaking.
Follow-up: How does currentColor help theming?
Why is user-uploaded SVG dangerous?(Advanced)
SVG allows script, event handlers, and foreignObject HTML. A 'logo upload' can steal session cookies when rendered inline. Mitigate: server-side sanitize, rasterize, CSP, serve from separate origin.
Follow-up: What tags would your allowlist include?
SVG vs canvas for a live dashboard?(Advanced)
Under ~500 interactive DOM nodes with a11y requirements — SVG/D3. Beyond that or needing pixel shaders — canvas/WebGL. Hybrid: SVG axes, canvas data layer (Observable plot pattern).
Follow-up: How do you test screen reader experience for SVG charts?
Try it yourself
Edit the HTML, CSS, or JS panels — the preview updates as you type.
Try it yourself
Summary
SVG is the production choice for icons, logos, and moderate data viz when accessibility and CSS theming matter — with SVGO discipline, XSS-safe uploads, explicit dimensions for CLS, and a clear handoff threshold to canvas for high-node workloads.