People Markets: icons and compact controls
On this page
- People Markets: icons and compact controls
- 1. The selected library
- 2. Size, stroke and spacing
- 3. Meaning registry
- 4. Interaction and accessible names
- 5. Checkbox specification
- 6. Radio specification
- 7. Dropdown selection
- 8. Scrollbar specification
- 9. Responsive application
- 10. Designing an addition
- 11. Implementation example
- 12. Review checklist
- Sources
Version 1.4 · 24 September 2026
Companion: people-markets-design-system-v1.4.html
Decision: Lucide for interface icons. Bricolage Grotesque, Instrument Sans and the approved color system remain unchanged.
1. The selected library
Use Lucide for interface actions, navigation, disclosure and status. The visual fit is a People Markets design decision: the outline forms sit comfortably beside Instrument Sans, and their restrained treatment leaves names and display typography prominent. A second general-purpose icon family is not needed.
The official library provides a 24 × 24 source grid, 2-unit strokes, rounded caps and joins, and Vue components that can be imported individually. The current Vue package is @lucide/vue; the official migration guide describes the move from lucide-vue-next. These are verified library facts, not assumptions about the dependencies in the People Markets repository. [L1–L3]
The HTML embeds a curated SVG reference subset. It does not fetch an icon font or icon CDN at runtime. The production application should use the named components from its reviewed, pinned package rather than copying icons from screenshots or depending on the mutable contents of a CDN.
The logo is not part of this decision. The People Markets mark, provider logos and photographs stay in their own asset system. Lucide explicitly separates interface pictograms from brand marks. [L5]
2. Size, stroke and spacing
| Role | Visible size | Stroke behavior | Typical placement |
|---|---|---|---|
| Compact icon | 16 × 16 px | 2 source units; approximately 1.33 px rendered | Dropdown indicator, menu row, small metadata action |
| Standard icon | 20 × 20 px | 2 source units; approximately 1.67 px rendered | Search, close, watch and ordinary icon buttons |
| Larger icon | 24 × 24 px | 2 source units; 2 px rendered | An occasional larger control or explanatory status |
| Checkbox tick | 14 × 14 px | 2.5 source units; approximately 1.46 px rendered | Only inside the 16 px checkbox box |
| Radio dot | 6 × 6 px | Solid centered circle | Only inside the 16 px radio outline |
The rendered stroke calculations use source stroke × displayed size ÷ 24. Keep ordinary strokes scaling with the viewBox. Do not mix constant-screen-width and scaling strokes arbitrarily; Lucide exposes non-scaling strokes as a separate behavior. [L4]
The checkbox tick is the one documented optical exception. Its slightly stronger stroke prevents the small positive mark from becoming fragile. Do not apply that exception to every icon on the page.
Use 6–8 px between a compact icon and its text. Use 10 px between a checkbox or radio mark and its label. Center a standard icon in a 44 × 44 px button. The 44 px target is the People Markets recommendation, not the visible icon size and not a claim that every WCAG AA target must be 44 px. The AA minimum criterion includes different dimensions and exceptions. [A1]
Use flex alignment rather than adjusting each icon with page-specific transforms. Preserve the square viewBox. Do not stretch, squeeze or cut the canvas to make a drawing fit. A dense glyph that is unclear at 16 px should be replaced by a simpler library symbol or visible text.
3. Meaning registry
The semantic key describes how People Markets uses the symbol. The library component is the actual imported drawing. Keep both recorded so a library rename or a product-language change can be reviewed centrally.
| Key | Lucide component | People Markets use |
|---|---|---|
check |
Check |
Selected value; not identity verification. |
minus |
Minus |
Mixed checkbox or a fixed decrease. |
plus |
Plus |
Add or increase a fixed setting. |
chevron-down |
ChevronDown |
Open a list of options. |
chevron-up |
ChevronUp |
Collapse an open list. |
chevron-right |
ChevronRight |
Collapsed supporting detail. |
chevron-left |
ChevronLeft |
Previous item in a local control. |
search |
Search |
Find a person or market. |
close |
X |
Close a dialog or clear a field. |
arrow |
ArrowRight |
Continue to the next screen. |
back |
ArrowLeft |
Return to the previous screen. |
external |
ExternalLink |
Open an external destination. |
copy |
Copy |
Copy a value or reference. |
star |
Star |
Watch or unwatch a named market. |
filters |
SlidersHorizontal |
Change the visible market filters. |
grid |
LayoutGrid |
Show market cards. |
list |
List |
Show a market list. |
up-right |
ArrowUpRight |
An observed rise; always include sign and period. |
down-right |
ArrowDownRight |
An observed fall; always include sign and period. |
info |
Info |
Explain a named field or condition. |
help |
CircleHelp |
Open a specific explanation. |
complete |
CircleCheck |
A confirmed completion, with status text. |
unknown |
CircleAlert |
An unresolved status; never infer failure. |
warning |
TriangleAlert |
A condition affecting an available action. |
pending |
Clock |
Pending or delayed; include its timestamp. |
locked |
LockKeyhole |
A specific unavailable control, not an assurance of safety. |
more |
Ellipsis |
Open a labeled group of additional actions. |
download |
Download |
Download a named file. |
expand |
Maximize2 |
Expand a chart or preview. |
contract |
Minimize2 |
Restore the previous view size. |
A shared symbol can cover closely related actions when the visible label disambiguates them: X closes a dialog or clears a field; Plus increases a fixed setting or adds an item. Do not use the same symbol for unrelated financial concepts. If a new interpretation is needed, add it to the registry and review the actual placement.
Specific boundaries
Check, chevron and mixed state. Check confirms a selected value. ChevronDown opens options. Minus indicates a partially selected checkbox group when contained in that group control. None is a substitute for the others.
Watch. Keep Star as the watch symbol in both states. A selected star may be filled; the button’s pressed state and visible wording identify whether the market is watched. Do not change the watch symbol into a check or a verification badge after selection.
Status. A complete-circle icon accompanies an authoritative completed state. An accepted request, pending request, partial fill or uncertain submission is not completed. The source status and its text remain the authority; an icon cannot resolve an ambiguous backend response.
Financial direction. An up-right arrow may accompany an observed positive change, alongside the signed value and measurement period. It must not imply a forecast, a recommendation, or a guarantee. A down-right arrow is not a generic error symbol. Price direction and user-interface errors have different meanings.
Safety and identity. Do not use a shield, lock or check to suggest that money is insured, a market is safe, or a person has approved a listing. Use a verified identity or partnership badge only when its exact claim and source are defined separately.
New concepts. Mark price, external reference, funding, collateral and liquidation need language before they need custom pictograms. A clear label is preferable to a newly invented icon that requires another explanation.
4. Interaction and accessible names
Buttons with visible labels
Keep the label and icon together inside a native button or link. The SVG is decorative and hidden from assistive technology. The text names the action. [L6]
<button type="button" class="btn secondary" @click="copyReference">
<PmIcon name="copy" :size="16" />
<span>Copy order reference</span>
</button>
Do not add a separate label such as “copy icon” to the SVG. It duplicates or distracts from the action.
Icon-only controls
Use an icon-only button only where the action is familiar and space is genuinely constrained. Keep a 44 px hit area. Put a specific accessible name on the button. Keep a visible explanation nearby for unfamiliar financial actions. [L6]
<button type="button" class="icon-btn" @click="closeReview">
<PmIcon name="close" />
<span class="sr-only">Close order review</span>
</button>
A tooltip may supplement that label but cannot be the only way to learn the action. Essential instructions must work without hover. Do not use an SVG with a click handler as a substitute for a button.
State behavior
Hover may change the surrounding surface or border immediately. Focus receives a visible outline around the interactive control. Pressed state must be exposed on a toggle. Disabled controls remain identifiable, with the reason nearby when it affects a task.
Do not bounce, spin, draw, morph, thicken or enlarge icons on hover. Disclosure indicators may reverse orientation immediately when a panel opens. A static Clock with explicit status text is sufficient for waiting; no decorative loading animation is required.
For an icon carrying meaning outside a labeled control, prefer an adjacent visible label. The chart legend must not depend on icons, hover or color alone. Keep the name, unit, series style and relevant time period readable.
Keyboard behavior
Focus belongs to the button, link, native input or composite control, not to its SVG. Tab reaches the action; Enter or Space activates it according to the native element. Keep focus in an open modal and return it to the opener on dismissal. Inline status feedback should not steal focus or delete the currently focused control.
5. Checkbox specification
Visible mark: 16 × 16 px, 1.5 px outline, 3 px corner radius.
Selected state: brand action fill and the contrasting 14 px Lucide Check glyph.
Mixed state: the same box and fill with an 8 × 1.5 px horizontal mark.
Label: 14–16 px Instrument Sans; 10 px gap from the mark; at least 44 px target height.
The tick uses a short downstroke and a longer rising stroke. It is an SVG path, not two equal borders rotated into a V. A SquareCheck icon must not be placed inside an already drawn checkbox, which would double its frame.
The full label is clickable. Multiple-line explanations can make the row taller without making the mark larger. In a selection card, align the mark with the first label line, not the vertical center of a long explanation.
The HTML enhancement leaves the native input responsible for focus, checked state, form semantics and keyboard behavior. A decorative sibling renders the visible box. Without enhancement, the native checkbox remains usable. Do not remove the input with display:none.
Keep unchecked, checked, mixed, disabled-unchecked, disabled-checked, invalid and keyboard-focus states. A mixed group state comes from its child values, not from a decorative class that can contradict the selection. indeterminate is a property of the native checkbox and is not the same thing as checked.
Use a persistent local explanation for errors. The border color alone does not explain what needs correction. Do not preselect consent or imply that ticking a box proves understanding.
6. Radio specification
Visible mark: 16 × 16 px circle with a 1.5 px outline.
Selected state: action-colored outline and a centered 6 px solid dot.
Label: the same type, gap and target dimensions as the checkbox.
A radio never contains a tick. The circle means one choice in a group; a square means an independent choice. A selection card repeats the same small radio rather than introducing a new oversized indicator.
Use native radio inputs sharing a name, within a named fieldset. Preserve their keyboard behavior. Unavailable options stay visibly unavailable and cannot be chosen. A consequential trade direction may start with no choice; do not preselect it merely to avoid an empty-looking form.
At small widths, stack cards while preserving the radio and full description. Do not shrink labels, increase the dot size or remove the explanation to force two choices onto one row.
7. Dropdown selection
The trigger uses a 16 px ChevronDown. The saved option uses a separate 16 px Check. Exploring another option changes its pale active background, not the saved check, until the user commits the choice. There is no left highlight border or inset selection rail. Keyboard and forced-colors focus remain visible. Escape restores the prior value.
Do not use a chevron as a selected-state marker or change a selected option’s text into an unlabeled icon. Reserve right-side room for the check so long labels do not collide with it. The popup retains its own thin native scrollbar when the options exceed the available height.
Keep the visible field label. The listbox pattern is for selecting a value; use a separate menu pattern for commands such as copying or exporting. Do not overload one unlabeled “more” dropdown with both kinds of behavior.
8. Scrollbar specification
The default treatment is a 4 px visible neutral line inside a 6 px lane, with rounded ends, a transparent track and no arrow buttons where the browser exposes those parts. The line is the thumb, not a decorative progress meter. Apply it to both axes and to the reference, popups, tables and product examples.
Keep native scrolling and thumb dragging. Do not replace scrolling with a JavaScript track, a draggable div or wheel-event interception. Do not hide overflow to make a screen appear cleaner. At 1,024 CSS px and below, ordinary market and data tables reflow into labeled cards. Only genuinely two-dimensional content retains a clearly labeled local horizontal scrolling region; the page itself still reflows.
The implementation has two paths. In browsers exposing WebKit scrollbar parts, it resets standard scrollbar values to auto before styling those parts. This matters because non-auto standard scrollbar-color or scrollbar-width values can override the pseudo-element styling. That override was capable of bringing back platform arrows despite a custom thumb rule. [S1]
In standards-only engines, request scrollbar-width: thin and the neutral thumb color. The exact width and arrow treatment remain browser/operating-system controlled. CSS cannot guarantee identical native chrome everywhere.
The reference offers Use system scrollbars as an explicit alternative and restores native rendering in forced-colors mode. Platform accessibility preferences take precedence over the visual rule. A fine scrollbar is not the only means of navigating a scroll region: preserve wheel, trackpad, touch and keyboard paths, and test actual usage.
The 44 px control-target recommendation is not a claim that a 4 px scrollbar has a 44 px hit area. The distinction is deliberate. Test precision and accessibility; allow the system setting when native sizing works better.
9. Responsive application
| Situation | Keep | Adapt |
|---|---|---|
| 320–639 px screen | 16 px checkbox/radio; 16 or 20 px icons; full labels | Stack long radio cards; use the whole row as the target; keep the popup within the viewport |
| 640–959 px screen | Same geometry and meanings | Use two columns only when labels and explanations fit |
| 960 px and wider | Same geometry and meanings | Increase content capacity, not icon scale; keep forms at a useful reading width |
| Narrow panel on a wide page | Same marks and semantic labels | Let the component respond to its actual container; do not assume a wide viewport means a wide control |
| Large text or browser zoom | Complete labels and descriptions | Allow controls to grow vertically; do not clip or shrink text |
| Forced colors | Native focus and selected-state semantics | Restore system form marks and scrollbars |
The reference’s scale control is for inspection. A 16 px icon inside a scaled-down iframe appears smaller on the physical screen. Assess control legibility at 100% display scale or in the full-size screen example, not only in a fitted preview.
10. Designing an addition
Search the approved registry first. If the needed meaning exists in Lucide, add the package component to the registry rather than drawing a substitute. Record its semantic key and the actual use case.
A custom icon is justified only by a repeated, specific product need that the library and clear text cannot satisfy. Before drawing, write the meaning, likely confusion and the visible label that will accompany it.
Use Lucide’s source specification: 24 × 24 canvas; at least 1 px clear space from the outside stroke to the canvas edge; 2-unit centered strokes; rounded caps and joins; and at least 2 px between separate details. Match established shape vocabulary and optical weight. [L1]
Inspect it beside Circle, Square, Search and Check at 16, 20 and 24 px, in both themes and at 1× and 2× display density. Avoid arbitrary gradients, fills, 3D treatments and tiny modifiers. The full-size design board is not enough evidence of small-size legibility.
The change record must include the source SVG, semantic key, owner, accessibility treatment, package/custom provenance, license and review date. Use a pm- prefix for genuinely custom symbols. Never modify an upstream drawing under its original library name without recording the fork.
Brand marks are not custom interface icons. Do not redraw the People Markets logo on this grid, or replace provider marks with approximate line drawings.
11. Implementation example
Create a bounded registry, not a dynamic import of every icon. The registry includes only approved components. Importing the entire library to resolve arbitrary server-provided names defeats the purpose of the selection. Named component imports are supported by Lucide’s Vue package. [L2]
// ui/icons.ts
import {
Check,
Minus,
Plus,
ChevronDown,
ChevronUp,
ChevronRight,
ChevronLeft,
Search,
X,
ArrowRight,
ArrowLeft,
ExternalLink,
Copy,
Star,
SlidersHorizontal,
LayoutGrid,
List,
ArrowUpRight,
ArrowDownRight,
Info,
CircleHelp,
CircleCheck,
CircleAlert,
TriangleAlert,
Clock,
LockKeyhole,
Ellipsis,
Download,
Maximize2,
Minimize2
} from '@lucide/vue';
export const icons = {
'check': Check,
'minus': Minus,
'plus': Plus,
'chevron-down': ChevronDown,
'chevron-up': ChevronUp,
'chevron-right': ChevronRight,
'chevron-left': ChevronLeft,
'search': Search,
'close': X,
'arrow': ArrowRight,
'back': ArrowLeft,
'external': ExternalLink,
'copy': Copy,
'star': Star,
'filters': SlidersHorizontal,
'grid': LayoutGrid,
'list': List,
'up-right': ArrowUpRight,
'down-right': ArrowDownRight,
'info': Info,
'help': CircleHelp,
'complete': CircleCheck,
'unknown': CircleAlert,
'warning': TriangleAlert,
'pending': Clock,
'locked': LockKeyhole,
'more': Ellipsis,
'download': Download,
'expand': Maximize2,
'contract': Minimize2,
} as const;
export type IconName = keyof typeof icons;
<!-- ui/PmIcon.vue -->
<script setup lang="ts">
import { computed } from 'vue';
import { icons, type IconName } from './icons';
const props = withDefaults(defineProps<{
name: IconName;
size?: 16 | 20 | 24;
selected?: boolean;
}>(), { size: 20, selected: false });
const component = computed(() => icons[props.name]);
const fill = computed(() =>
props.name === 'star' && props.selected ? 'currentColor' : 'none'
);
</script>
<template>
<component
:is="component"
:size="size"
:stroke-width="2"
:non-scaling-stroke="false"
:fill="fill"
color="currentColor"
aria-hidden="true"
focusable="false"
class="pm-icon"
/>
</template>
<style scoped>
.pm-icon { flex: none; vertical-align: middle; }
</style>
The wrapper intentionally renders decorative SVGs only. A semantic button/link or adjacent visible text carries the meaning. Validate unknown external icon names at the boundary; do not silently substitute a misleading symbol. Keep the numeric size prop authoritative rather than overriding every SVG to 20 px in an unrelated global rule.
The standalone HTML demonstrates the same sizing and semantics without requiring Vue. This Vue example is an implementation pattern, not a claim that the current repository was built or typechecked here. Inspect the actual package exports, run the repository’s checks and pin the reviewed dependency before integration.
12. Review checklist
A change is ready for integration when all of the following are true:
- The symbol comes from the approved library/registry, or the custom addition has a recorded review.
- Check, chevron, mixed selection and completion remain visually distinct.
- Checkbox and radio marks measure 16 × 16 px, with no overlapping label or clipped focus ring.
- The associated target is generous even though the mark is small.
- Single and multiple selection retain native keyboard behavior and accurate state.
- Icon-only controls have specific accessible names; visible labels remain for unfamiliar financial actions.
- The selected star stays a star; status symbols never imply a financial result the service has not confirmed.
- Thin scrollbar parts have no painted arrows in supporting browsers; the system alternative works.
- Narrow widths, long labels, both themes, forced colors and remote-asset failure are checked.
- No new motion, icon font, second icon family or improvised logo has been introduced.
The actual reference-file test results are recorded in the HTML. Browser layout checks do not establish real-device usability, assistive-technology conformance or production trading readiness.
Sources
[L1] Lucide icon specification.
[L2] Lucide Vue getting started.
[L3] Lucide Vue migration.
[L4] Lucide Vue stroke behavior.
[L5] Lucide brand-logo statement.
[L6] Lucide accessibility guidance.
[S1] MDN: scrollbar parts and standard-property precedence.
[A1] W3C: target size, minimum.
[License] Lucide and Feather-derived icon notices.
Library and browser references were reviewed on 24 September 2026. Token values, semantic mappings, sizes, exception handling and component conventions are People Markets design decisions. Font files are not included.