界面图标

操作、方向与状态使用同一套精确绘制的 SVG。固定 20px 光学网格,统一线宽和端点;可输出服务端 HTML 或原生 DOM,无字体依赖。次要操作在悬停或键盘聚焦时显现,触屏始终可见。

file
terminal
branch
line-numbers
wrap
calendar
close
check
chevron-down
chevron-up
chevron-right
chevron-left
arrow-right
arrow-left
arrow-up
arrow-down
plus
minus
sort
search
sun
moon
benzhen
pixel
more
copy
edit
link
trash
spinner
circle-check
circle-error
circle-info
triangle-alert
refresh
external

同一个图形在不同字号下保持对齐。

12px 16px 20px 24px 32px

次要动作保留固定槽位。悬停这一行,或按 Tab 聚焦,移除按钮显现;内容不会位移。

产品设计规范
html
<div class="icon-demo-grid"><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M6 2.5h5.5L16 7v9.5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-12a2 2 0 0 1 2-2ZM11.5 2.5V7H16"></path></svg><code>file</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M5 3.5h10a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-9a2 2 0 0 1 2-2ZM6 7l3 3-3 3M11 13h3"></path></svg><code>terminal</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M6 6v8M14 6v2a4 4 0 0 1-4 4H6M8 4a2 2 0 1 1-4 0 2 2 0 0 1 4 0ZM8 16a2 2 0 1 1-4 0 2 2 0 0 1 4 0ZM16 4a2 2 0 1 1-4 0 2 2 0 0 1 4 0Z"></path></svg><code>branch</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M3 5h2M3 10h2M3 15h2M8 5h9M8 10h9M8 15h9"></path></svg><code>line-numbers</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M3 5h14M3 10h10a3 3 0 0 1 0 6h-3M12.5 13.5 10 16l2.5 2.5"></path></svg><code>wrap</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M5.5 4h9A2.5 2.5 0 0 1 17 6.5v8a2.5 2.5 0 0 1-2.5 2.5h-9A2.5 2.5 0 0 1 3 14.5v-8A2.5 2.5 0 0 1 5.5 4ZM6.5 2.5v3M13.5 2.5v3M3 8h14M6.5 11h.1M10 11h.1M13.5 11h.1M6.5 14h.1M10 14h.1"></path></svg><code>calendar</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M6 6l8 8M14 6l-8 8"></path></svg><code>close</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M4.5 10.2l3.6 3.6 7.4-7.6"></path></svg><code>check</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M5.5 7.75 10 12.25l4.5-4.5"></path></svg><code>chevron-down</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M5.5 12.25 10 7.75l4.5 4.5"></path></svg><code>chevron-up</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M7.75 5.5 12.25 10l-4.5 4.5"></path></svg><code>chevron-right</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M12.25 5.5 7.75 10l4.5 4.5"></path></svg><code>chevron-left</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M3.5 10h13M11 4.5l5.5 5.5-5.5 5.5"></path></svg><code>arrow-right</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M16.5 10h-13M9 4.5 3.5 10 9 15.5"></path></svg><code>arrow-left</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M10 16.5v-13M4.5 9 10 3.5 15.5 9"></path></svg><code>arrow-up</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M10 3.5v13M4.5 11l5.5 5.5 5.5-5.5"></path></svg><code>arrow-down</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M10 4v12M4 10h12"></path></svg><code>plus</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M4 10h12"></path></svg><code>minus</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M6 15V4M3 7l3-3 3 3M14 5v11M11 13l3 3 3-3"></path></svg><code>sort</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M13.3 13.3 17 17M14.5 8.5a6 6 0 1 1-12 0 6 6 0 0 1 12 0"></path></svg><code>search</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M13.5 10a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0M10 1.75v1.5M10 16.75v1.5M1.75 10h1.5M16.75 10h1.5M4.17 4.17l1.06 1.06M14.77 14.77l1.06 1.06M4.17 15.83l1.06-1.06M14.77 5.23l1.06-1.06"></path></svg><code>sun</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M17.25 11.15A7.5 7.5 0 0 1 8.85 2.75a7.5 7.5 0 1 0 8.4 8.4Z"></path></svg><code>moon</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M6.5 3h7A3.5 3.5 0 0 1 17 6.5v7a3.5 3.5 0 0 1-3.5 3.5h-7A3.5 3.5 0 0 1 3 13.5v-7A3.5 3.5 0 0 1 6.5 3ZM7 10l3-3 3 3-3 3Z"></path></svg><code>benzhen</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M3 3h5v5H3ZM12 3h5v5h-5ZM3 12h5v5H3ZM12 12h5v5h-5Z"></path></svg><code>pixel</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M4 9.9v.2M10 9.9v.2M16 9.9v.2"></path></svg><code>more</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M7 7h8a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2V7ZM13 7V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h2"></path></svg><code>copy</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M11.5 4.5l4 4M4 12l9-9a1.4 1.4 0 0 1 2 0l2 2a1.4 1.4 0 0 1 0 2l-9 9-5 1Z"></path></svg><code>edit</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M8 6l2-2a4.2 4.2 0 0 1 6 6l-2 2M12 14l-2 2a4.2 4.2 0 0 1-6-6l2-2M7 13l6-6"></path></svg><code>link</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M3.5 5.5h13M7 5.5V3h6v2.5M5 5.5l.7 11.5h8.6L15 5.5M8 9v5M12 9v5"></path></svg><code>trash</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M10 3a7 7 0 1 1-7 7"></path></svg><code>spinner</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0ZM6 10l2.7 2.7 5.3-5.4"></path></svg><code>circle-check</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0ZM7.2 7.2l5.6 5.6M12.8 7.2l-5.6 5.6"></path></svg><code>circle-error</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0ZM10 9v5M10 6.1v.15"></path></svg><code>circle-info</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M8.7 3.5a1.5 1.5 0 0 1 2.6 0l6.4 11.3a1.5 1.5 0 0 1-1.3 2.2H3.6a1.5 1.5 0 0 1-1.3-2.2ZM10 7.2v4.4M10 14v.15"></path></svg><code>triangle-alert</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M16.5 7.2A7 7 0 0 0 4.3 5.9L2.5 8M2.5 3.5V8H7M3.5 12.8a7 7 0 0 0 12.2 1.3l1.8-2.1M13 12h4.5v4.5"></path></svg><code>refresh</code></div><div class="icon-demo-cell"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M11.5 3H17v5.5M17 3l-8 8M8 3H5a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-3"></path></svg><code>external</code></div></div>  <p class="doc-note">同一个图形在不同字号下保持对齐。</p>  <div class="demo-row"><span><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="12" height="12" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M4.5 10.2l3.6 3.6 7.4-7.6"></path></svg> 12px</span><span><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M4.5 10.2l3.6 3.6 7.4-7.6"></path></svg> 16px</span><span><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M4.5 10.2l3.6 3.6 7.4-7.6"></path></svg> 20px</span><span><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="24" height="24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M4.5 10.2l3.6 3.6 7.4-7.6"></path></svg> 24px</span><span><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="32" height="32" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M4.5 10.2l3.6 3.6 7.4-7.6"></path></svg> 32px</span></div>  <p class="doc-note">次要动作保留固定槽位。悬停这一行,或按 Tab 聚焦,移除按钮显现;内容不会位移。</p>  <div class="icon-demo-quiet" id="icon-demo-quiet"><span>产品设计规范</span><button type="button" class="icen-icon-action" data-icen-reveal aria-label="移除规范"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M6 6l8 8M14 6l-8 8"></path></svg></button></div>  <p id="icon-demo-removed" hidden role="status">规范已移除。<button type="button" class="icen-btn icen-btn-sm" id="icon-demo-undo">撤销</button></p>

安装

bun add @icen.ai/ui

一行引入该组件(CSS 与 behavior 自动带上,无需关心内部 CSS 文件名):

js
import '@icen.ai/ui/kit/icon';

也可以用脚手架直接打印引入行:

bash
bunx --bun @icen.ai/ui add icon

Astro 项目注意:kit 入口里的 CSS import 在页面 <script> 里会被 Astro 的 client bundle 摇掉——请改在布局 frontmatter 里引 CSS(import '@icen.ai/ui/components/icon.css';),JS 行为仍可走 kit。Vite SPA / webpack 项目无此问题。

用法

js
import { iconHTML, createIcon, registerIcon } from '@icen.ai/ui/kit/icon';// 在服务端模板中输出 SVG;所有标签和属性均转义。const html = iconHTML('chevron-down', { size: 16 });// 在已经有名称的按钮中,图标默认 aria-hidden,不重复朗读。button.setAttribute('aria-label', '关闭');const closeIcon = createIcon('close');if (closeIcon) button.append(closeIcon);// 独立图标提供 label 后自动带 role="img"。const completeIcon = createIcon('check', { label: '已完成', size: 20 });if (completeIcon) container.append(completeIcon);// 自有图形使用同一光学网格。只接受 SVG path,不执行脚本或注入 HTML。registerIcon('app-mark', 'M3 3h14v14H3Z');iconHTML('app-mark');// 标记驱动的次要动作:.icen-icon-action + data-icen-reveal。// 父级 hover / focus-within 显示,触屏常显。不要隐藏主要操作或关键状态。// 方向图标的 RTL 语义由所在组件决定,通用图标不会擅自翻转。