MobTranslate styleguide

Iconography

Use a coherent symbol system, clear names and text alternatives. Icons support meaning; they do not establish cultural authority.

When an icon helps

Use familiar icons to reinforce an action or status. Keep a visible label when the meaning is unfamiliar, ambiguous or consequential. A dictionary source link, permission request or publication decision benefits from explicit text. An icon-only action saves space only when its meaning is reliably understood.

RoleTreatmentAccessible contract
Decorative companionSVG beside a visible labelaria-hidden="true"; the label supplies meaning
Icon-only buttonSymbol inside a real buttonA specific accessible name, visible focus and usable target
Status symbolSymbol plus status textText distinguishes the state without color
Standalone meaningful imageNamed image or SVGA text alternative describing its purpose
Directional navigationArrow appropriate to reading directionAction name stays explicit; mirror only when semantics require

Geometry and optical consistency

  • Choose a single licensed icon family in the consuming app and use it consistently. Do not mix filled, outline and decorative families casually.
  • The authored specimens below use a 24×24 coordinate system, 2-unit strokes, round caps and joins. They are documentation examples, not a new exported icon package.
  • Use 16px for restrained supporting symbols, 20–24px for common control icons, and 32px only when the hierarchy warrants it. Keep stroke weight and optical centering coherent.
  • The visible glyph size is separate from the hit area. A 20px glyph may sit inside a 44px or larger touch target.
  • Use currentColor so the symbol inherits the semantic foreground. Test meaningful icons and focus boundaries for non-text contrast.

Trim, live area and keyline geometry

Separate the complete graphic box from the live area and the optical silhouette. The reference uses a 24-unit baseline with a 20-unit live area and a 2-unit inset. Its square, circle and vertical/horizontal rectangle keylines help differently shaped symbols have comparable visual weight; they are construction guides rather than masks that every outline must fill.

The compiled inspector overlays an original bookmark on those guides. A path’s centerline is not its complete painted extent: stroke width, caps and joins add space. Check the full painted boundary against the trim box. Inspect the delivered rendering at the actual CSS size/device scale; enlarging a screenshot or meeting a coordinate grid does not establish pixel-perfect output.

Reference guideDimensions in model unitsInspection
Trim box24 × 24Keep the complete painted symbol within its bounds
Live area20 × 20, inset 2Default composition area; deliberate optical correction may extend beyond it
Square keyline18 × 18Compare mass rather than forcing all paths onto the square
Circular keylineDiameter 20Inspect the outer stroke as well as the centerline
Vertical/horizontal keylines16 × 20 / 20 × 16Balance tall and wide forms against other family members

Anatomy, stroke and optical correction

Identify the bounding area, stroke, terminal, corner, counter stroke and counter area before changing a drawing. Preserve recognizable negative space at small sizes; increasing stroke can close a counter even when the outer box remains unchanged. Optical corrections should improve clarity without skewing the underlying family geometry.

Keep a family’s construction rules coherent. The Material design reference distinguishes exterior/interior corner treatment and terminal conventions across styles. Our authored SVG specimens use their own round joins and selectable round/flat terminals; they are not Material Symbols outlines. The stroke selector changes actual geometric width, not a font weight axis.

Avoid unnecessary complexity, perspective and dimensional effects in a small functional icon. Simplify the meaningful structure first; check whether a local stroke adjustment or a different optical drawing retains recognition. Never make an unfamiliar symbol the sole instruction for a consequential action.

Material Symbols styles and variable axes

The reference distinguishes Outlined, Rounded and Sharp Symbol styles from the legacy Material Icons set. Choose a licensed coherent family for the product and record the exact delivered asset/version. A similarly named SVG or an icon-font family declaration does not install that family. Existing authored examples remain independent SVGs.

A supporting Material Symbols variable font exposes weight, fill, grade and optical size. Use its actual axis metadata and documented ranges; inspect the loaded face, fallback and rendered glyphs before declaring that an axis worked. SVG stroke/fill changes in this lab do not emulate grade or optical drawing. The Typography inspector demonstrates real variable-font delivery and axis ownership with a separate licensed text face.

AxisDesign questionFailure to avoid
wghtHow much stroke emphasis is appropriate?Treating a coordinate as SVG stroke pixels; extreme weight closing counters
FILLWould an outlined/filled change reinforce a selected state?Using fill alone instead of explicit selected/pressed semantics
GRADDoes a finer optical weight adjustment improve the combination?Treating grade as a contrast repair or assuming identical coordinates across fonts look identical
opszWhich size-specific drawing fits the displayed use?Scaling a single vector and calling it an optical master; confusing axis coordinate with CSS size

Text alignment, optical sizes and targets

Match perceived text/icon weight and hierarchy, then inspect alignment in the real layout. The reference includes 20, 24, 40 and 48 optical sizes and a Symbol baseline offset near 11.5% of text size. These are starting references for that family, not universal SVG rules or CSS dp conversions. Font metrics, line boxes, fallback and labels still need measurement.

The inspector supports 16–48 CSS-pixel glyphs independently of the native button target. Below 20, keep explicit labels for complex or essential meaning. Material’s reference targets vary by input context; this project keeps at least a 44px primary-action contract. Small glyphs do not justify shrinking the interactive area or crowding neighboring controls.

For inline text, use a stable layout wrapper and preserve room for wrapping. The direction specimen uses text plus an aria-hidden arrow; it is not a navigation control. Test larger text and long labels without rasterizing the label, shifting it with arbitrary absolute offsets or making a tooltip the only name.

Localization and audience review

Recognition depends on audience, age, technology familiarity and local context. Keep navigation labels and test unfamiliar symbols with the people performing the task. A familiar product convention is a hypothesis about recognition, not proof that every reader understands it. Record the intended action and evaluate alternatives in context.

Color and imagery can carry different associations. Avoid treating broad regional anecdotes as rules for a specific community. Use source-backed local guidance and qualified review for cultural identity or contributed artwork. Do not substitute a flag, animal or ornamental motif for a verified language/community label.

Mirror only reading-order movement that actually changes in the target direction. Retain the identity of source images, logos, written characters and media controls. The lab mirrors the arrow while preserving the bookmark and its local saved state; broader component/portal direction needs its own test.

Asset delivery, composition and handoff

Record format, license, provenance, version, viewBox or font face, size, styling policy, optical variants and intended names. Export only the required assets, preserve their drawing proportions and verify actual loads. A copy/paste tool can transfer geometry or CSS; it cannot establish semantic approval or rights to unrelated artwork.

For SVG companions, currentColor follows the selected semantic foreground and aria-hidden avoids duplicate names. For meaningful standalone images, provide a contextual alternative. For icon fonts, hide glyph/ligature machinery from assistive technology and give the enclosing control a real label. Retain a readable control if a font or asset fails; raw ligature text is not an acceptable essential-action fallback.

Review light/dark/forced-colors output, small and large glyphs, target separation, text spacing, direction, keyboard state and asset failure. Inspect the actual accessibility tree, including name and pressed/selected state. Choose qualified audience testing for recognition; numeric geometry alone cannot certify meaning.

Live icon and action lab

Next page (direction specimen)

Save entry changes local example state. The arrow is a decorative direction specimen beside text, not a navigation control. Geometric stroke scales to 2.00 CSS pixels before rasterization; this is not optical-size or font-grade adjustment.

Icon construction grid24-unit trim box, 20-unit live area with 2-unit inset. Selected keyline: square. Original bookmark overlaid for comparison, using stroke 2 and round terminals. Coordinates are model units, not device dp.

Trim 24 × 24; live area 20 × 20; inset 2 on each side. Keyline square. The drawing scales to the page; guides are construction references, not a claim of pixel-perfect rendering or recognizability.

Compiled icon inspector

tsx
'use client';
import {useId,useState} from 'react';
import './iconography-explorer.css';

export function IconographyExplorer(){
  const id=useId();
  const [size,setSize]=useState('24');
  const [stroke,setStroke]=useState('2');
  const [cap,setCap]=useState<'round'|'butt'>('round');
  const [keyline,setKeyline]=useState('square');
  const [saved,setSaved]=useState(false);
  const [rtl,setRtl]=useState(false);
  const [status,setStatus]=useState('');
  return <div className="icon-lab" data-icon-lab>
    <label>Icon size<select data-icon-size className="mt-input" value={size} onChange={event=>setSize(event.target.value)}>{[16,20,24,32,40,48].map(value=><option key={value} value={value}>{value}px</option>)}</select></label>
    <label>SVG stroke in viewBox units<select data-icon-stroke className="mt-input" value={stroke} onChange={event=>setStroke(event.target.value)}>{[1.5,2,3].map(value=><option key={value}>{value}</option>)}</select></label>
    <label>SVG stroke terminals<select data-icon-cap className="mt-input" value={cap} onChange={event=>setCap(event.target.value as typeof cap)}><option value="round">Round</option><option value="butt">Square-ended (butt)</option></select></label>
    <label className="icon-check"><input data-icon-rtl type="checkbox" checked={rtl} onChange={event=>setRtl(event.target.checked)} />Right-to-left navigation</label>
    <div data-icon-preview dir={rtl?'rtl':'ltr'}>
      <button data-icon-save type="button" aria-label="Save entry" aria-pressed={saved} onClick={()=>{setSaved(previous=>!previous);setStatus(saved?'Example entry removed from saved items.':'Example entry saved.');}}>
        <svg viewBox="0 0 24 24" width={size} height={size} aria-hidden="true" focusable="false" fill={saved?'currentColor':'none'} stroke="currentColor" strokeWidth={stroke} strokeLinecap={cap} strokeLinejoin="round"><path d="M6 4h12v16l-6-4-6 4z" /></svg>
      </button>
      <span className="icon-direction"><svg viewBox="0 0 24 24" width={size} height={size} aria-hidden="true" focusable="false" fill="none" stroke="currentColor" strokeWidth={stroke} strokeLinecap={cap} strokeLinejoin="round"><path data-icon-arrow d="M5 12h14m-6-6 6 6-6 6" transform={rtl?'translate(24 0) scale(-1 1)':undefined} /></svg><span dir="auto">Next page (direction specimen)</span></span>
    </div>
    <p role="status">{status}</p><p>Save entry changes local example state. The arrow is a decorative direction specimen beside text, not a navigation control. Geometric stroke scales to {(Number(size)*Number(stroke)/24).toFixed(2)} CSS pixels before rasterization; this is not optical-size or font-grade adjustment.</p>
    <label>Reference keyline<select data-icon-keyline className="mt-input" value={keyline} onChange={event=>setKeyline(event.target.value)}><option value="square">18 × 18 square</option><option value="circle">20 diameter circle</option><option value="vertical">16 × 20 vertical rectangle</option><option value="horizontal">20 × 16 horizontal rectangle</option></select></label>
    <svg data-icon-grid viewBox="0 0 24 24" role="img" aria-labelledby={`${id}-title ${id}-desc`}>
      <title id={`${id}-title`}>Icon construction grid</title><desc id={`${id}-desc`}>24-unit trim box, 20-unit live area with 2-unit inset. Selected keyline: {keyline}. Original bookmark overlaid for comparison, using stroke {stroke} and {cap} terminals. Coordinates are model units, not device dp.</desc>
      <g stroke="var(--color-border)" strokeWidth="0.06" aria-hidden="true">{Array.from({length:25},(_,i)=><g key={i}><path d={`M ${i} 0 V 24`} /><path d={`M 0 ${i} H 24`} /></g>)}</g>
      <rect x=".1" y=".1" width="23.8" height="23.8" fill="none" stroke="currentColor" strokeWidth=".2" />
      <rect x="2" y="2" width="20" height="20" fill="none" stroke="currentColor" strokeWidth=".2" strokeDasharray=".6 .4" />
      <g data-icon-keyline-shape fill="none" stroke="var(--color-primary)" strokeWidth=".25">
        {keyline==='circle'?<circle cx="12" cy="12" r="10" />:<rect x={keyline==='vertical'?4:keyline==='horizontal'?2:3} y={keyline==='vertical'?2:keyline==='horizontal'?4:3} width={keyline==='vertical'?16:keyline==='horizontal'?20:18} height={keyline==='vertical'?20:keyline==='horizontal'?16:18} />}
      </g>
      <path data-icon-grid-mark d="M6 4h12v16l-6-4-6 4z" fill="none" stroke="currentColor" strokeWidth={stroke} strokeLinecap={cap} strokeLinejoin="round" />
    </svg>
    <p data-icon-geometry>Trim 24 × 24; live area 20 × 20; inset 2 on each side. Keyline {keyline}. The drawing scales to the page; guides are construction references, not a claim of pixel-perfect rendering or recognizability.</p>
  </div>;
}

Inspector stylesheet

css
.icon-lab { display: grid; gap: 1rem; min-inline-size: 0; }
.icon-lab label, .icon-lab p { min-inline-size: 0; overflow-wrap: anywhere; }
.icon-lab .mt-input { display: block; inline-size: 100%; margin-block-start: .5rem; }
.icon-lab .icon-check { display: flex; align-items: center; gap: .75rem; min-block-size: 44px; }
.icon-check input { flex: 0 0 auto; }
.icon-lab [data-icon-preview] { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem; padding: 12px; border: 1px solid var(--color-border); border-radius: var(--radius-lg); }
.icon-lab [data-icon-save] { display: flex; justify-content: center; align-items: center; min-inline-size: 44px; min-block-size: 44px; padding: 8px; border: 1px solid var(--color-muted-foreground); border-radius: var(--radius-md); flex: 0 0 auto; }
.icon-direction { display: flex; align-items: center; gap: .5rem; min-inline-size: 0; }
.icon-direction > svg { flex: 0 0 auto; }
.icon-direction > span { min-inline-size: 0; overflow-wrap: anywhere; }
.icon-lab [data-icon-grid] { inline-size: 240px; max-inline-size: 100%; block-size: auto; overflow: visible; }
@media(forced-colors:active) { .icon-lab [data-icon-preview], .icon-lab [data-icon-save] { border-color: CanvasText; } .icon-lab [data-icon-grid] * { stroke: CanvasText; } }

Naming and toggle behavior

Name an action by what it does: Open source details or Play recording. Avoid names such as Arrow icon. For a toggle, use a stable accessible label with aria-pressed and report its state; for a changing command, update the action label deliberately. A tooltip is supporting help, not the only accessible name.

tsx
<button type="button" aria-label="Save entry"
  aria-pressed={saved} onClick={() => setSaved(!saved)}>
  <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
    <path d="M6 4h12v16l-6-4-6 4z" />
  </svg>
</button>
<p role="status">{saved ? "Entry saved" : "Entry removed from saved items"}</p>

Direction, language and culture

  • Mirror forward/back arrows when they express reading-order navigation. Do not mirror written characters, logos, source images or media playback symbols automatically.
  • Do not use flags as a substitute for language names or generic cultural symbols as a substitute for verified identity.
  • Check whether a symbol has a different meaning for the actual audience. Product conventions do not override local cultural authority.
  • Use permitted assets with recorded license and provenance. A generated illustration is not a real source photograph.

Failure cases

  • Avoid placing a click handler on an SVG instead of a button.
  • Avoid a title attribute as the only label for an essential control.
  • Do not use a checkmark alone to imply qualified language review. Pair the exact review status with its evidence.
  • Avoid emoji as interchangeable UI icons; rendering, naming and meaning vary across platforms.
  • Do not set every SVG to role="img" when it only repeats adjacent text; duplicate announcements make controls harder to use.

Verification

  • Inspect the icon-only button in the accessibility tree: its name is Save entry and its pressed state changes.
  • Activate it with Enter, Space and a pointer, and confirm the visible state and status announcement agree.
  • Compare 16, 20, 24, 32, 40 and 48px glyphs without shrinking the action target.
  • Inspect both themes and forced-colors mode. Check the directional arrow in RTL while the bookmark retains its shape.
  • Review unfamiliar symbols with representative users rather than assuming a recognizable drawing communicates the intended action.