HKChat Style Guide
Every piece of the HKChat interface, and when to use it.
1 · Start
How to read this
You do not need to be a designer or a developer to use this page. If you are making anything that carries the HKChat brand, this tells you which pieces to use.
| One sentence | What the thing is. |
| Look | The real component, exported straight from Figma. |
| Status | Every state it can be in. |
| Usage | When to use it, and when not to. |
| Token | A saved setting. Instead of "purple" we say primary/default. Change it once, everything follows. |
| Component | A reusable piece, like a button. |
| State | A version of a piece. Resting, pressed, switched off. |
Code: Storybook — the source of truth for anything shipping.
If this page and Storybook disagree, Storybook is right.
2 · Foundation
Colour
Colour carries meaning. It is never decoration.
Brand
Text and icons
Feedback
Each has an -on partner for text placed on top. Always use the partner.
Backgrounds
The full spectrum
157 raw colours behind the named ones. Never use these directly — they carry no meaning and do not change with dark mode.
Never invent a shade because one looks nicer. Never use colour as the only signal.
Text
Six styles, in three languages — 繁體, 简体 and English.
港話通 · 香港人的 AI 助手
港話通 · 香港人的 AI 助手
港話通 · 香港人的 AI 助手
港話通 · 香港人的 AI 助手
港話通 · 香港人的 AI 助手
港話通 · 香港人的 AI 助手
港话通 · 香港人的 AI 助手
港话通 · 香港人的 AI 助手
港话通 · 香港人的 AI 助手
港话通 · 香港人的 AI 助手
港话通 · 香港人的 AI 助手
港话通 · 香港人的 AI 助手
The quick brown fox
The quick brown fox
The quick brown fox
The quick brown fox
The quick brown fox
The quick brown fox
| Style | Size | Use for |
|---|---|---|
| H1 | 22px Bold | Page titles. One per screen. |
| H2 | 16px Medium | Section headings. |
| Body | 14px Regular | Reading text. Large buttons. |
| Label | 14px Bold / SemiBold | Emphasis at body size. |
| Caption | 12px Regular | Labels, timestamps, small buttons. |
| XS | 8px Regular | Tiny metadata only. |
Each exists three times — TC · SC · ENG. Pick the one matching the language on screen.
Floor: never render below ~11px. Touch targets and spacing do not scale with the font.
Never a size not in the table. No 13px, no 15px, no 18px.
Shape
Three corner roundings. That is the whole system.
| Rounding | Goes on |
|---|---|
radius/sm 8 | Small things inside other things — tags, tabs, agent buttons, SnackToast. |
radius/md 16 | Things that hold other things — cards, inputs, sheets, widgets. |
radius/full 999 | Buttons and anything pill shaped. |
Space
Gaps come from a fixed ladder, and everything is a multiple of 4.
space/14px · icon to its labelspace/28px · inside small buttonsspace/312px · between related itemsspace/416px · card padding, screen edge margin, and the gap between two buttonsspace/624px · between groupsspace/832px · between sectionsspace/1248px · big breaksspace/2496px · very rare, empty statesFullsize single & double button spec
What matters here is the margin from the screen edge and the gap between buttons — not the button's own width.
| Screen | Width | Edge margin | Gap between two |
|---|---|---|---|
| Mobile | 390 → 767 | 16 each side | 16 |
| Tablet | 768 → 1199 | column caps, centred | 16 |
| Desktop | 1200 and up | column caps, centred | 16 |
Never let a single button keep stretching on a wide screen. Above tablet the column stops and centres. Never mix a small and a large button in one group.
Icon size
Five icon sizes, each tied to where the icon sits.
| Token | Size | Where |
|---|---|---|
icon/xs | 16px | inside small buttons |
icon/sm | 20px | inside large buttons, social actions |
icon/md | 24px | icon buttons, bottom menu |
icon/lg | 32px | empty states |
icon/xl | 40px | very rare, feature moments |
Elevation
How far something floats above the page.
Elevation
Two heights. One glow. Shadow + surface always travel together.
PENDING — surface/raised and surface/overlay do not exist yet. One token cannot be a different token per mode, so these two must be created before the pairing above can be applied. Awaiting Bon.
| Level | Use for | Needs |
|---|---|---|
| Flat | Almost everything. | a border — invisible without one |
| Raised | Chat input, cards that move. | elevation/raised |
| Overlay | Sheets, menus, dialogs, toasts. | elevation/overlay |
| Glow | Widgets only. Decoration, not height. | glow/brand |
Never use a shadow to group things — use a border or space. Never make a shadow lighter in dark mode.
3 · Action
Button graph
Every button is a weight crossed with a content type — pick one from each.
Never two Primary buttons in the same area.
Primary Button
The main action on a screen — filled, so it is impossible to miss.
| State | What it means |
|---|---|
| Default | Resting. |
| Pressed | While a finger or mouse is down. |
| Disabled | Cannot be used right now. |
| Hover | Mouse over it. Built in code, not inside Figma. |
| Focus | Reached by keyboard. Built in code, not inside Figma. |
Never two on one screen area. Width hugs its own text.
Secondary Button
A supporting action — outlined, so it sits quietly beside the primary one.
Same five states as Primary — Default, Pressed, Disabled drawn in Figma; Hover and Focus built in code, not inside Figma.
Never alone for the main action. If it is the main action, it should be Primary.
It has nowhere to live yet. A Danger button only makes sense where there is a confirm step, and HKChat has no Dialog component. Until there is one, do not place a Danger button anywhere.
Error and Danger use the same red but face opposite directions in time: Error reports what already happened. Danger warns about what is about to.
Icon & text button
A button whose whole label is its picture — used in headers, toolbars and rows that repeat.
| Rule | Value |
|---|---|
| States | Default · Pressed · Disabled. Hover and Focus in code, not inside Figma. |
| Tap area | 44 × 44 minimum — bigger than the picture you can see |
| Picture | 24px, line style |
| Hidden name | required, always — real text, never a code key |
Never for the main action. Never for delete, unsubscribe or log out. Never for a picture you had to think about.
選單, never common.more.Tab
A row of filters — press one and the content below changes.
| State | Look |
|---|---|
| Default | white fill, grey border, regular weight |
| Selected | soft purple fill, purple border, bold |
34px tall · rounding 8 · 12px text.
Never leave none selected. If it does not filter anything, it is a Tag.
Social
The like, comment, share and save actions on a post.
| Type | default | pressed |
|---|---|---|
| heart · 讚 | line, grey | filled, purple |
| comment · 評論 | line, grey | filled, purple |
| share · 分享 | line, grey | filled, purple |
| star · 收藏 | line, grey | filled, purple |
Never purple for a resting social action. Purple here means on, not important.
4 · Navigation
Bottom Menu
The bar at the bottom of the app — four places you can go, always the same four.
| State | Look |
|---|---|
| Default | grey, line icon |
| Selected | purple, filled icon |
Selected changes two things — colour and icon fill. Colour alone is not enough for colour-blind users.
Never a fifth item. Never an action here — this bar goes places, it does not do things.
Hamburger menu
The panel that slides in when you press ☰ — it holds past conversations, search and settings.
如何幫我找出過去三年立法會
如何幫我找出過去三年立法會
颱風預測資訊
如何幫我找出過去三年立法會
如何幫我找出過去三年立法會
如何幫我找出過去三年立法會
如何幫我找出過去三年立法會
颱風預測資訊
如何幫我找出過去三年立法會
如何幫我找出過去三年立法會
| State | Behaviour |
|---|---|
| Closed | Off screen. Only the ☰ button is visible. |
| Opening | Slides in from the left. The page behind dims. |
| Open | Sits at overlay height. The page behind stays visible but is not pressable. |
| Closing | Press ☰ again, press the dimmed area, or swipe left. |
Never a main action in here. Never open it over another overlay.
5 · Information
SnackToast
A short message confirming something just happened — it fades on its own.
| Status | Means |
|---|---|
| Default | Something happened. Neutral. |
| Success | It worked. |
| Error | It failed. |
| Plus: an optional icon, and at most one action such as 重試. | |
Timing: 4 seconds alone, 6–8 with an action. One at a time.
Never for form errors, decisions, or anything over two lines. Never auto-hide an error needing a retry. Never two actions.
User Pill
Shows who someone is — a small round picture and their name.
| No states | This is information, not a control. You cannot press it. |
| Picture | 26px round. Use the person's photo if they have one. |
| No photo | The first letter of the account name, white, on a colour. |
| Colour | From the brand set, so the same person is always the same colour. |
| Name | 12px Medium, 4px after the picture. |
Never make it look pressable. If pressing opens a profile, that is a different component and needs a 44×44 tap area.
Tag
A small label describing what something is — you cannot press it.
| No states | Purely informative. It describes. It does not respond. |
| Size | 22px tall · rounding 8 · 12px Medium |
Tag and Tab share the same rounding. Tell them apart by height — Tag 22px, Tab 34px — and by colour.
Never make a Tag look pressable or give it a selected state. If people can press it, it is a Tab.
6–7 · Exploration
Input bar Exploration
The box you type into. Five variants — and they combine.
如何在香港续领特区护照
想搵旺角邊間蛋撻?定睇紅隧交通? 想搵旺角邊間蛋撻?定睇紅隧交通?想搵旺角邊間蛋撻?定睇紅
想搵旺角邊間蛋撻?定睇紅隧交通? 想搵旺角邊間蛋撻?定睇紅隧交通?想搵旺角邊間蛋撻?定睇紅想搵旺角邊間蛋撻?定睇紅隧交通? 想搵旺角邊間蛋撻?定睇紅隧交通?想搵旺角邊間蛋撻?定睇紅
一起參與討論吧!
一起參與討論吧!
想搵旺角邊間蛋撻?定睇紅隧交通?
想搵旺角邊間蛋撻?定睇紅隧交通?
一起參與討論吧!
| Group | Variant | What it is |
|---|---|---|
| General | text | typing, including when the text overflows |
| recording | voice input running | |
| attachment | a file has been added | |
| Situational | guiding questions | suggested prompts sit above the box |
| agent selected | an agent is active, so the box changes |
That combination is what still needs deciding. The five variants are a starting point for the argument, not a finished set.
Agent button Exploration
Picks which AI skill answers you.
| State | Look |
|---|---|
| Default | surface fill, grey border, muted text |
| Selected | muted fill, purple bold text |
36px tall · rounding 8 · 12px text.
Never remove the word — these are never icon-only. Nobody can guess an agent from a picture.
Widget Exploration
A block the AI builds to show one task as structured information you can check, or an action, instead of a paragraph you have to read.
| 1 · One task | It does a single thing. Two things means two widgets. |
| 2 · Structured | Its content is fields, not prose. Title, time, destination — things you can scan and verify. |
| 3 · Worth showing | There is something to check, decide or watch. Nothing to check? Use plain text. |
一起參與討論吧!
一起參與討論吧!
收到!撳「匯入日曆」就可以加入你嘅日曆。或者喺聊天輸入框話我知你想改啲咩!
一起參與討論吧!
ONE example of a conversational widget. The pattern here is not the rule — other widgets will behave differently.
| 1 · Two actions, maximum | One primary, one optional secondary, at the bottom. More than two means it should not be a widget. |
| 2 · No second screen inside | No tabs, no drill-in, no deeper navigation. If it needs a second view, it is two widgets or a whole page. |
| 3 · No scrolling inside | It grows to fit its content, up to the screen height. It never gets its own scrollbar. |
| 4 · Never repeat the app | No search box, no second text field, no keyboard. The app already has those. A widget that duplicates them competes with the thing it lives inside. |
| 5 · Bigger means more, not larger | A taller widget shows more rows — not the same rows at a bigger size. |
Don't — no editing inside a widget, changes happen by talking · no tabs, no drill-in, no second screen · never repeat what the app already does · never blank, if there is nothing to show use text.
One deliberate difference: OpenAI allows inline editing inside a card. HKChat does not.
8 · Interactive
Hover
One rule covers every component — no component gets its own hover design.
| State | What happens | When |
|---|---|---|
| Hover | the element's own text colour over itself at 8% · 4% on large cards | mouse only |
| Pressed | the same film at 12% | mouse and finger |
| Focus | 2px purple ring, 2px offset | keyboard only |
White text gives a white film. Black text gives a black film. Works in dark mode by itself.
Never design hover per component. Never change text colour on hover. Never use hover as the only way to reveal something.
@media (hover: hover), meaning "only if there is a real mouse."HKChat Style Guide · Version 3
Every component above is exported from Figma 港話通HKChat V2.1 → ⚠️V2R2 → 📤 STYLE GUIDE EXPORT.
Code: Storybook. Sections 6 and 7 are exploration. 18 August 2026.