[GH-ISSUE #15271] app/ui: inline SVG icons duplicated across components #35528

Open
opened 2026-04-22 20:05:47 -05:00 by GiteaMirror · 1 comment
Owner

Originally created by @matteocelani on GitHub (Apr 3, 2026).
Original GitHub issue: https://github.com/ollama/ollama/issues/15271

What is the issue?

The app UI currently has 31 inline SVG icons spread across 9 component files, totaling ~205 lines of raw SVG markup. Several icons are duplicated across components (e.g. close/X, edit pencil, sidebar toggle).

Files affected:

Component Inline SVGs SVG lines / total lines
Message.tsx 14 85 / 991
ChatForm.tsx 6 46 / 997
ThinkButton.tsx 3 19 / 162
ModelPicker.tsx 2 15 / 348
layout.tsx 2 11 / 82
ChatSidebar.tsx 1 6 / 391
Downloading.tsx 1 5 / 57
WebSearchButton.tsx 1 9 / 41
Logo.tsx 1 9 / 64

Problems this causes:

  1. Duplication: the same icon (e.g. close X, copy) appears in multiple files. A visual change requires updating every copy independently.
  2. Readability: large components like Message.tsx and ChatForm.tsx (~1000 lines each) contain significant SVG markup mixed with component logic, making reviews harder.
  3. No inventory: there is no way to see which custom icons exist without searching raw SVG paths across the codebase.

Heroicons already covers the standard icons. The ~15 unique custom icons (sidebar toggle, submit arrow, stop square, edit pencil, copy, etc.) are the ones pasted inline.

This is not blocking anything — just flagging it as a potential improvement for maintainability as the app UI grows.

Originally created by @matteocelani on GitHub (Apr 3, 2026). Original GitHub issue: https://github.com/ollama/ollama/issues/15271 ### What is the issue? The app UI currently has **31 inline SVG icons** spread across 9 component files, totaling ~205 lines of raw SVG markup. Several icons are duplicated across components (e.g. close/X, edit pencil, sidebar toggle). **Files affected:** | Component | Inline SVGs | SVG lines / total lines | |---|---|---| | Message.tsx | 14 | 85 / 991 | | ChatForm.tsx | 6 | 46 / 997 | | ThinkButton.tsx | 3 | 19 / 162 | | ModelPicker.tsx | 2 | 15 / 348 | | layout.tsx | 2 | 11 / 82 | | ChatSidebar.tsx | 1 | 6 / 391 | | Downloading.tsx | 1 | 5 / 57 | | WebSearchButton.tsx | 1 | 9 / 41 | | Logo.tsx | 1 | 9 / 64 | **Problems this causes:** 1. **Duplication**: the same icon (e.g. close X, copy) appears in multiple files. A visual change requires updating every copy independently. 2. **Readability**: large components like `Message.tsx` and `ChatForm.tsx` (~1000 lines each) contain significant SVG markup mixed with component logic, making reviews harder. 3. **No inventory**: there is no way to see which custom icons exist without searching raw SVG paths across the codebase. Heroicons already covers the standard icons. The ~15 unique custom icons (sidebar toggle, submit arrow, stop square, edit pencil, copy, etc.) are the ones pasted inline. This is not blocking anything — just flagging it as a potential improvement for maintainability as the app UI grows.
Author
Owner

@matteocelani commented on GitHub (Apr 3, 2026):

I opened this issue to discuss before submitting a PR, as suggested in CONTRIBUTING.md.
I've thought about three possible approaches and would like to hear which one (if any) aligns with the project's direction.

1) Extract into React components (zero new dependencies)
Create src/components/icons/ with one .tsx file per custom icon, each exporting a typed component accepting standard SVG props. No tooling changes needed.

2) Use SVGR via Vite plugin (SVGR · vite-plugin-svgr)
Import .svg files directly as React components. Adds one dev dependency but is widely adopted in the React/Vite ecosystem and automates the SVG → component conversion.

3) Replace with Heroicons where possible
Some inline SVGs may have equivalents in the already-installed @heroicons/react. This reduces the custom icon count, but icons like the sidebar toggle, submit arrow, and stop square have no Heroicons match and would still need approach 1 or 2.

My recommendation would be approach 2, it keeps SVG files as the single source of truth (easier for designers to update), avoids manual boilerplate for each icon, and scales well as the app grows. The dev dependency cost is minimal since it's only a build-time plugin.

Let me know which direction you'd prefer and I'll open a PR.

<!-- gh-comment-id:4182949957 --> @matteocelani commented on GitHub (Apr 3, 2026): I opened this issue to discuss before submitting a PR, as suggested in CONTRIBUTING.md. I've thought about three possible approaches and would like to hear which one (if any) aligns with the project's direction. **1) Extract into React components (zero new dependencies)** Create `src/components/icons/` with one `.tsx` file per custom icon, each exporting a typed component accepting standard SVG props. No tooling changes needed. **2) Use SVGR via Vite plugin ([SVGR](https://react-svgr.com) · [vite-plugin-svgr](https://github.com/pd4d10/vite-plugin-svgr))** Import `.svg` files directly as React components. Adds one dev dependency but is widely adopted in the React/Vite ecosystem and automates the SVG → component conversion. **3) Replace with Heroicons where possible** Some inline SVGs may have equivalents in the already-installed `@heroicons/react`. This reduces the custom icon count, but icons like the sidebar toggle, submit arrow, and stop square have no Heroicons match and would still need approach 1 or 2. My recommendation would be **approach 2**, it keeps SVG files as the single source of truth (easier for designers to update), avoids manual boilerplate for each icon, and scales well as the app grows. The dev dependency cost is minimal since it's only a build-time plugin. Let me know which direction you'd prefer and I'll open a PR.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/ollama#35528