Skip to main content
For teams who need deeper styling control while staying within the UIKit framework. Component Styling allows you to override CSS, customize individual components, and implement advanced theming.

Styling Control

Override styles with custom config json

Component Targeting

Customize specific components and pages

Advanced Theming

Complex color schemes and typography

UIKit Framework

Still within the UIKit ecosystem

When to Choose Component Styling

Component Styling is ideal when you need: Custom brand experiences - Basic colors and fonts
Granular control - Target specific components or pages
Advanced theming - Complex color schemes and typography
Framework benefits - Want to stay within UIKit’s ecosystem
Simple branding - Dynamic UI is easier for basic needs
Complex layouts - Fork & Extend offers more freedom
Custom components - Need source code access for new components

Configuration Model

Component Styling uses a single config.json surface for cross-platform overrides. It layers on top of default UIKit tokens (and Dynamic UI if present) using a path pattern: page_id/component_id/element_id with wildcards (*).

Path Pattern & Levels

Specific beats generic: Element overrides > Component overrides > Page overrides > Global theme.

Supported Theme Tokens

Every key below may be set under theme.light and theme.dark. Any key you omit falls back to the default shown. Defaults are identical across platforms — they ship in the same config template.
Where each token applies. Thirteen tokens resolve across every UIKit feature: primary_color, secondary_color, base_color, base_shade1_color through base_shade4_color, base_inverse_color, alert_color, background_color, background_shade1_color, highlight_color, and toast_background_color.The rest belong to a revised color set that currently drives chat components only. Setting them has no effect on other features yet — those continue to resolve through the thirteen above, and adopt the expanded set in a later release.

Core

Brand shades

Variants of primary_color and secondary_color used for hover, pressed, disabled and emphasis states.

Neutral greys

A light-to-dark ramp used for borders, dividers, skeletons and muted text. These are mode-independent by default — set them per mode if your dark theme needs a different ramp.

Destructive

Escalating scale for destructive actions and error states.

Overlays

Semi-transparent fills for scrims, media overlays and pressed states. Values carry an alpha channel (#RRGGBBAA).

Fixed and feature colors

Minimal Config Skeleton

Theme Application & Preferred Mode

Set the app’s theme resolution strategy with preferred_theme:
Use default unless you have a business requirement to lock theme (e.g., brand guidelines for launch).

Targeting Examples

Override a whole screen. Great for hero / camera / immersive surfaces.
Adjust reusable functional blocks everywhere.
Fine-grain tweak for single control.

Reference: Allowed IDs

Exclusions

Remove (hide) specific elements by adding their path to excludes:
Excluding structural elements (like a required close button) may degrade usability. Test flows after any exclusion.

Precedence & Conflict Resolution

Group related overrides together to prevent accidental shadowing by later blocks.

Custom Config File (iOS)

iOS only. On Android, Flutter, and React Native, the config JSON is loaded differently per platform. On iOS, use setConfigFile to load a local JSON file from your app bundle at initialisation time.
By default UIKit reads its bundled config.json. setConfigFile lets you supply a replacement from your own app bundle — useful for per-environment configs, white-label builds, or shipping your own defaults without modifying UIKit source.

Implementation

Call setConfigFile before presenting any UIKit view. Config values are read at render time — calling it after the first render may leave some components using the default config.
If the file path is invalid or the JSON is malformed, UIKit silently falls back to its bundled defaults. Validate your JSON locally before shipping.

Custom Asset Bundle (iOS)

iOS only. On Android, Flutter, and React Native, image overrides are handled through the config.json element keys (e.g. “close_icon”: “close.png”).
In addition to config.json, iOS lets you supply a custom Bundle containing your own images. UIKit uses it as a fallback — your assets are loaded only for image names that do not exist in UIKit’s own bundle.
If you provide an image with the same name as a UIKit default asset, UIKit’s copy wins. To replace an exposed icon, point its config.json key to a uniquely named file and provide that file in your custom bundle.

How It Works

1

UIKit bundle checked first

If the image name exists in UIKit’s own bundle, that version is always used.
2

Custom bundle as fallback

Only when the name is not found in UIKit’s bundle does it fall through to your registered custom bundle.
3

Not found anywhere

If the image is absent from both bundles, UIKit renders a placeholder rather than crashing.

Implementation

Call setCustomAssetBundle once during app initialisation, after AmityUIKit4Manager.setup(client:).
Register the bundle before any UIKit view is presented. Images are resolved at render time — late registration may cause some views to display the wrong asset.

Troubleshooting

Verify the asset is included in the bundle you registered:
Check that the file name, extension, and capitalisation match exactly what is referenced in config.json.
An asset with the same name in UIKit’s bundle always wins. Rename your asset uniquely and update the matching config.json icon key to point to the new name.
Ensure the image file appears under Copy Bundle Resources in Build Phases. Loose PNG/PDF files (not inside an .xcassets catalog) must be added manually.

Best Practices

Token First

Change global tokens before per-element overrides.

Progressive Specificity

Escalate from page → component → element only when needed.

Consistency

Reuse colors; avoid random hex proliferation.

Auditable Changes

Document rationale in PR descriptions.

Dark Mode QA

Visually inspect every high-contrast surface.

Minimal Exclusions

Prefer styling adjustments over removal.

Overriding Navigation Behaviour

Navigation can be customized without forking by overriding the provided Behaviour classes. UIKit isolates navigation & event hooks into behaviour objects per page/component so you can inject custom flows (e.g., presenting a different creation screen, analytics, guards) while keeping styling overrides separate.

Behaviour Architecture

  • Each major screen/component exposes a Behaviour (iOS) / Behavior (Android) class with overridable navigation methods.
  • A top-level AmityUIKit4Manager.behaviour (iOS) / AmityUIKit4Manager.behavior (Android) aggregates these instances.
  • Replace only the concrete behaviour you need; leave others at default.

Override Example

Only override the specific methods you need; keep defaults for forward compatibility.

Advanced iOS Navigation (Swipe Back & SwiftUI Hosting)

UIKit v4 pages are predominantly SwiftUI, embedded in UINavigationController via helper controllers: To preserve the interactive swipe‑to‑go‑back gesture while customizing appearance, UIKit globally overrides navigation gesture delegate methods. You can supply your own gesture behaviour logic via AmitySwipeToBackGestureBehavior.
Keep gesture logic lightweight—long operations here can block UI responsiveness.

When to Escalate

If navigation changes require altering internal view composition (e.g., embedding a new container architecture), consider moving to Fork & Extend. Simple route substitutions, analytics, permission gates, and gesture tweaks belong here.

Next Steps

Dynamic UI

Remote token updates

Advanced Customization

Fork & extend source