| name | arkui-api-design |
| description | This skill should be used when the user asks to "design ArkUI API", "add component property", "create Modifier method", "review ArkUI API", "deprecate API", "write JSDOC for ArkUI", or mentions OpenHarmony API design standards. Provides comprehensive guidance for ArkUI component API design following OpenHarmony coding guidelines, including static/dynamic interface synchronization, SDK compilation, and verification. |
| version | 2.0.0 |
ArkUI API Design Skill
This skill provides comprehensive guidance for designing, reviewing, and maintaining ArkUI component APIs that follow OpenHarmony Application TypeScript/JavaScript coding guidelines.
Core Design Principles
1. Follow OpenHarmony Coding Standards
All API definitions and code examples must comply with the OpenHarmony Application TypeScript/JavaScript Coding Guide. Key standards include:
- Naming conventions: Use camelCase for properties and methods, PascalCase for types/interfaces
- Type safety: Provide proper TypeScript type definitions for all parameters
- Code style: Follow 4-space indentation, consistent formatting
- Documentation: Comprehensive JSDOC comments for all public APIs
For detailed standards, refer to: references/OpenHarmony-Application-Typescript-JavaScript-coding-guide.md
2. Synchronize Static and Dynamic Interfaces
CRITICAL: When adding or modifying component properties, you must update both static and dynamic interface files:
Static API (.static.d.ets)
- Location:
OpenHarmony/interface/sdk-js/api/arkui/component/<component>.static.d.ets
- Purpose: Declarative UI API for ArkTS static type system
- Usage: Component declaration in
@Builder functions
- JSDOC Tags: Add
@static after @since [version] (e.g., @since 26 static)
- Example:
declare class Text {
content: string | Resource;
constructor(content: string | Resource);
}
Dynamic API (.d.ts Attribute Interface)
- Location:
OpenHarmony/interface/sdk-js/api/@internal/component/ets/<component>.d.ts
- Purpose: Imperative modifier API for command-style property setting
- Usage: Chained property modification
- JSDOC Tags: Add
dynamic after @since [version] (e.g., @since 26 dynamic)
- Example:
declare class TextAttribute extends CommonMethod<TextAttribute> {
content(value: string | Resource): TextAttribute;
}
Note: The *Modifier.d.ts files in arkui/ directory only define the Modifier class (for AttributeModifier pattern), not the Attribute interface itself.
Synchronization Rules
| Scenario | Static API | Dynamic API |
|---|
| Add property | Add to class/interface | Add to Attribute class |
| Deprecate property | Mark as @deprecated | Mark as @deprecated |
| Change signature | Update class definition | Update Attribute method |
| File location | arkui/component/*.static.d.ets | @internal/component/ets/*.d.ts |
| Version tag | @since X static | @since X dynamic |
| Return type | Use this for chainable | Use concrete Attribute type |
3. Support Resource Type for Configurable Properties
IMPORTANT: Not all properties need Resource type support. Only add Resource type when the property is intended to be configured through resource files (theming, i18n, etc.).
When to support Resource type:
- ✅ YES: Colors, fonts, sizes, strings, images - anything developers might configure through resource files for theming or internationalization
- ❌ NO: State flags, mode selectors, event callbacks - these are runtime-only configurations
Type Simplification Rule:
CRITICAL: Only use ResourceStr for NEW APIs (API 13+). Do NOT use ResourceStr to modify existing APIs (API 12 and earlier).
When to use ResourceStr:
- ✅ YES: For NEW properties/methods (introduced in API 13 or later)
- ❌ NO: For existing properties/methods (API 12 and earlier)
content(value: ResourceStr): TextAttribute
content(value: string | Resource): TextAttribute
fontSize(value: number | string | Length | ResourceStr): TextAttribute
Examples of properties that SHOULD support Resource:
fontSize(value: number | string | Length | Resource): TextAttribute
fontSize(value: number | string | Length | ResourceStr): TextAttribute
Text().fontSize(16)
Text().fontSize('16vp')
Text().fontSize($r('app.float.font_size_large'))
Text().fontSize(16)
Text().fontSize('16vp')
Text().fontSize($r('app.float.font_size_large'))
Examples of properties that SHOULD NOT support Resource:
stateEffect(value: boolean): ButtonAttribute
enabled(value: boolean): CommonMethod
onClick(callback: () => void): CommonMethod
Benefits of ResourceStr support (for NEW APIs only):
- Enables centralized theme management through resource files
- Supports internationalization with locale-specific resources
- Allows dynamic theming without code changes
- Type simplification: Use
ResourceStr instead of string | Resource
- Backward compatibility: Preserve existing API signatures for API 12 and earlier
4. Document undefined/null Behavior
JSDOC comments must explicitly specify how undefined and null values are handled:
fontSize(value: number | string | Length | Resource | undefined | null): TextAttribute;
Common patterns:
undefined → Restore default value
null → Remove setting, use inherited value
- Invalid values → Throw error with clear message
5. Use vp as Default Length Unit
Always use vp (virtual pixels) as default unit for length measurements:
width(value: number | string): ButtonAttribute
width(value: Length): ButtonAttribute
width(value: number): ButtonAttribute
6. Specify Constraints in JSDOC
JSDOC comments must include specification limits and constraints:
borderRadius(value: number | string | Length): CommonMethod;
Required documentation:
- Valid ranges (min/max values)
- Special value handling (negative, zero, etc.)
- Unit of measurement
- Clamping behavior (if applicable)
7. Consider Cross-Component Impact
When adding common properties, evaluate impact on all components:
Before adding common property:
- Check if property applies to most components (layout, style, event)
- Define consistent behavior across component types
- Document component-specific exceptions (if any)
- Consider backward compatibility
Example common properties:
- Layout:
width(), height(), padding(), margin()
- Style:
opacity(), visibility(), borderRadius()
- Event:
onClick(), onTouch()
8. Use Correct Terminology in JSDOC
CRITICAL: The phrase "Called when" must ONLY be used for event callback functions and lifecycle methods that are invoked by the framework. It MUST NOT be used for property setters, configuration methods, or attribute modifiers.
Proper Usage of "Called when"
✅ CORRECT: Event callbacks and lifecycle methods
onClick(callback: Callback<ClickEvent>): PasteButtonAttribute;
onProgress(callback: Callback<PlaybackInfo>): VideoAttribute;
onScrollFrameBegin(callback: (offset: number, state: ScrollState) => ScrollOffset): ListAttribute;
onReachEnd(callback: () => void): WaterFlowAttribute;
❌ INCORRECT: Property setters and configuration methods
fontSize(value: number | string | Resource): TextAttribute;
fontSize(value: number | string | Length | Resource): TextAttribute;
stroke(value: ResourceColor): ShapeAttribute;
stroke(value: ResourceColor): ShapeAttribute;
alignItems(value: AlignItems): ;
(: ): ;
Decision Tree for JSDOC Wording
Is this an event callback or lifecycle method?
├─ Yes → Use "Called when" or "Callback invoked when"
│ Examples: onClick, onScroll, onAppear, onDisAppear
│
└─ No → Use action verbs (Sets, Specifies, Configures, Enables/Disables)
Examples: fontSize(), fontWeight(), padding(), stateEffect()
Standard Wording Patterns
| API Type | Correct Phrasing | Examples |
|---|
| Property setters | "Sets the [property]." / "Specifies the [property]." | Sets the font size., Specifies the text color. |
| Configuration methods | "Configures the [feature]." / "Enables/Disables the [feature]." | Enables the state effect., Configures the scroll behavior. |
| Event callbacks | "Called when [event]." / "Callback invoked when [event]." | Called when clicked., Called when the scroll position changes. |
| Lifecycle methods | "Called when [lifecycle event]." | Called when the component appears., Called when the component is about to disappear. |
Common Mistakes to Avoid
-
"Called when the [property] is set" - This is the most common incorrect pattern
- ❌
Called when the font weight is set.
- ✅
Sets the font weight of the text.
-
"Called when [action]" for non-callback methods - Confuses property setters with callbacks
- ❌
Called when drawing a polygon. (for a property setter)
- ✅
Sets the drawing options for the polygon.
-
Passive voice for active configuration - Use active verbs for setter methods
- ❌
When the border color is set...
- ✅
Sets the border color of the component.
Examples of Corrected JSDOC
fontStyle(value: FontStyle): TextAttribute;
fontWeight(value: number | FontWeight | ResourceStr): TextAttribute;
textAlign(value: TextAlign): TextAttribute;
fill(value: ResourceColor): ShapeAttribute;
(: ): ;
(: ): ;
(: ): ;
9. Respect Interface Directory Boundaries
During API design and compilation verification, work only with files within interface/ directory:
Allowed modifications:
interface/sdk-js/api/arkui/component/*.static.d.ets - Static API definitions
interface/sdk-js/api/@internal/component/ets/*.d.ts - Dynamic API definitions (Attribute classes)
interface/sdk-js/api/arkui/*Modifier.d.ts - Modifier class definitions (for AttributeModifier pattern)
- Type definition files (*.d.ts, *.static.d.ets)
Do NOT modify:
- Framework implementation code in
ace_engine/
- Component pattern files
- Layout or render implementations
API Design Workflow
Complete Workflow for New Component Properties
1. Design API
├─ Define property types and constraints
├─ Document undefined/null behavior
└─ Check cross-component impact
2. Create Static API (.static.d.ets)
├─ Add property to component class
├─ Write complete JSDOC
└─ Include @since, @syscap tags
3. Create Dynamic API (@internal/component/ets/*.d.ts)
├─ Add method to Attribute class
├─ Match signature with static API
└─ Synchronize JSDOC documentation
4. Verify Type Safety
├─ Check TypeScript compilation
├─ Validate type definitions
└─ Ensure signature consistency
5. Build SDK
├─ Run SDK build command
└─ Monitor compilation errors
6. Verify SDK Output
├─ Check generated API files
├─ Verify new APIs are exported
└─ Test API availability
For New Component APIs
- Design API interface with proper TypeScript types
- Create Static API (
component/*.static.d.ets)
- Define component class with properties
- Add constructor and methods
- Write complete JSDOC comments
- Create Dynamic API (
@internal/component/ets/*.d.ts)
- Define Attribute class methods
- Add all property methods
- Sync with static API signatures
- Add JSDOC comments including:
- Parameter descriptions
- undefined/null handling
- Value constraints and ranges
- Default values
- @since version
- @syscap capability
- @throws documentation (if applicable)
- Support Resource type for theme-able properties
- Specify units (default to vp for lengths)
- Verify cross-component impact if adding common property
- Build SDK to verify compilation
For API Reviews
Use the following checklist to verify:
For API Deprecation
CRITICAL: When deprecating an API, you MUST mark BOTH the static API property/method AND the corresponding dynamic API method as @deprecated.
- Mark both static and dynamic APIs as
@deprecated
- Provide migration path in JSDOC
- Specify removal version (@obsoleted)
- Update documentation and examples
Synchronization Requirement:
- If you deprecate a property in static API → MUST deprecate in dynamic API
- If you deprecate a method in static API → MUST deprecate in dynamic API
- Both must have matching @deprecated, @obsoleted, @see, and @migration tags
SDK Build and Verification
Building the SDK
After completing API design changes, build the SDK to verify compilation and generate output:
./build.sh --export-para PYCACHE_ENABLE:true --product-name ohos-sdk --ccache
Build Parameters:
--export-para PYCACHE_ENABLE:true - Enable Python cache for faster builds
--product-name ohos-sdk - Build SDK target
--ccache - Use compiler cache for incremental builds
Build Output Location:
out/ohos-sdk/
├── interfaces/
│ └── sdk-js/
│ └── api/
│ └── arkui/
│ ├── component/ # Generated .static.d.ets files
│ │ ├── button.static.d.ets
│ │ ├── text.static.d.ets
│ │ └── ...
│ ├── ButtonModifier.d.ts # Generated .d.ts files
│ ├── TextModifier.d.ts
│ └── ...
Verification Steps
After SDK build completes successfully:
1. Verify Static API
grep -n "yourNewProperty" out/ohos-sdk/interfaces/sdk-js/api/arkui/component/<yourcomponent>.static.d.ets
2. Verify Dynamic API
grep -n "yourNewMethod" out/ohos-sdk/interfaces/sdk-js/api/@internal/component/ets/<your_component>.d.ts
3. Verification Checklist
4. Common Build Issues
| Issue | Symptom | Solution |
|---|
| Type mismatch | Build fails with type error | Check signatures match between static/dynamic APIs |
| Missing import | Cannot find type | Add proper import statements |
| JSDOC error | Documentation warning | Fix JSDOC syntax, ensure all tags are valid |
| Sync error | API exists in one file only | Add to both static and dynamic files |
Code Examples
Example 1: Complete Static + Dynamic API
Static API: button.static.d.ets
declare class Button {
type: ButtonType;
stateEffect: boolean;
constructor(label: string | Resource, options?: ButtonOptions);
}
Dynamic API: button.d.ts (in @internal/component/ets/)
declare class ButtonAttribute extends CommonMethod<ButtonAttribute> {
type(value: ButtonType): ButtonAttribute;
stateEffect(value: boolean): ButtonAttribute;
}
Example 2: Adding a New Property
Adding iconSize to Button
Static API Update:
declare class Button {
iconSize: number | string;
}
Dynamic API Update:
declare class ButtonAttribute extends CommonMethod<ButtonAttribute> {
iconSize(value: number | string | Length | undefined): ButtonAttribute;
}
Example 3: API Deprecation
Deprecating setFontSize in favor of fontSize
Static API:
declare class Text {
fontSize: number | string | Resource;
setFontSize(value: number | string | Resource): void;
}
Dynamic API:
declare class TextAttribute extends CommonMethod<TextAttribute> {
fontSize(value: number | string | Length | Resource | undefined | null): TextAttribute;
setFontSize(value: number | string | Resource): TextAttribute;
}
Common Pitfalls
Missing Static/Dynamic Synchronization
declare class Text {
content: string | Resource;
}
declare class Text {
content: string | Resource;
}
declare class TextAttribute extends CommonMethod<TextAttribute> {
content(value: string | Resource): TextAttribute;
}
Inconsistent Signatures
iconSize: number;
iconSize(value: number | string | Resource): ButtonAttribute;
iconSize: number | string;
iconSize(value: number | string): ButtonAttribute;
Incomplete JSDOC
width(value: number): CommonMethod;
width(value: number | string | Length | undefined): CommonMethod;
Forgetting Resource Type
fontSize(value: number | string): TextAttribute;
fontSize(value: number | string | Length | Resource): TextAttribute;
Additional Resources
Coding Standards
references/OpenHarmony-Application-Typescript-JavaScript-coding-guide.md
- OpenHarmony TypeScript/JavaScript Coding Guide (official complete version)
- Contains naming conventions, type definitions, code formatting, and all coding standards
- All design principles in this skill are based on this document
Example Code
examples/interface-definition.ts - Complete interface definition example
examples/modifier-implementation.ts - Modifier method implementation example
examples/deprecation-pattern.ts - API deprecation with migration example
examples/static-dynamic-sync.ts - Static/Dynamic API synchronization example
Knowledge Base References
Quick Reference
Essential JSDOC Tags
Important Tag Rules:
- Static API (
.static.d.ets): Use @since X static format (e.g., @since 26 static)
- Dynamic API (
*Modifier.d.ts): Use @since X dynamic format (e.g., @since 26 dynamic)
- All APIs: Add
@stagemodelonly tag to indicate stage model only
Type Support Decision Tree
Does the parameter accept length values?
├─ Yes → Add Length and Resource types
└─ No → Is it theme-able (color, size, string)?
├─ Yes → Add Resource type
└─ No → Use basic types (number | string | undefined | null)
Default Value Documentation
"If undefined, restores to default [value] ([unit])."
"If null, removes setting and uses inherited value."
Static vs Dynamic API Quick Reference
| Aspect | Static API (.static.d.ets) | Dynamic API (*.d.ts) |
|---|
| File Location | arkui/component/ | @internal/component/ets/ |
| Usage | Text({ content: 'Hello' }) | Text().content('Hello') |
| Type | Class declaration | Class extending CommonMethod |
| Pattern | Constructor-based | Method chaining |
| Return Type | N/A (properties) | Concrete Attribute type |
| Version Tag | @since X static | @since X dynamic |
| Both Required | ✅ Yes | ✅ Yes |
Static/Dynamic Synchronization Checklist
Before finalizing any API, verify:
Files Updated
Signatures Match
JSDOC Complete
Return Type Convention
Version Tags
Compilation Verified
Common Mistakes to Avoid
1. Only Updating One File
❌ Bad: Only static file updated
default lineSpacing(value: LengthMetrics | undefined): this;
✅ Good: Both files updated
default lineSpacing(value: LengthMetrics | undefined, options?: LineSpacingOptions): this;
lineSpacing(value: LengthMetrics | undefined, options?: LineSpacingOptions): RichEditorAttribute;
2. Inconsistent Parameter Types
❌ Bad: Different parameter types
default lineSpacing(value: LengthMetrics): this;
lineSpacing(value: LengthMetrics | undefined): RichEditorAttribute;
✅ Good: Identical parameter types
default lineSpacing(value: LengthMetrics | undefined, options?: LineSpacingOptions): this;
lineSpacing(value: LengthMetrics | undefined, options?: LineSpacingOptions): RichEditorAttribute;
3. Missing Version Tags
❌ Bad: Generic version tags
✅ Good: Proper version tags
4. Wrong File Location
❌ Bad: Looking for dynamic API in wrong location
✅ Good: Correct file location