ai-skills/skills/valdi-custom-view/skill.md
Applies to: **/*.tsx files using <custom-view> elements.
<custom-view> Element<custom-view> renders a platform-native view inside a Valdi component. Each platform resolves the view by class name.
<custom-view
androidClass="com.snap.modules.my_module.MyNativeView"
iosClass="SCMyNativeView"
macosClass="SCMyNativeView"
webClass="MyWebViewClassName"
width="100%"
height={120}
/>
| Attribute | Platform | Resolution |
|---|---|---|
androidClass | Android | Reflection via ReflectionViewFactory; needs @RegisterAttributesBinder |
iosClass | iOS | ObjC class name; must be linked via ios_deps |
macosClass | macOS | NSClassFromString(); must be linked via macos_deps |
webClass | Web | Looked up in WebViewClassRegistry; registered via webPolyglotViews export |
(Context) constructor. An @RegisterAttributesBinder-annotated binder is discovered from assets at runtime.NSView/UIView subclass linked into the binary.NSView subclass.webClass name is matched against the WebViewClassRegistry. Register by exporting webPolyglotViews from a web polyglot entry file (see web-polyglot.md rule).Instead of resolving by class name, you can pass a ViewFactory object directly. This is useful when the factory is provided by a parent component or constructed dynamically:
import { ViewFactory } from 'valdi_tsx/src/ViewFactory';
interface MyViewModel {
viewFactory?: ViewFactory;
}
class MyComponent extends Component<MyViewModel> {
onRender(): void {
if (this.viewModel.viewFactory) {
<custom-view style={styles.container} viewFactory={this.viewModel.viewFactory} />;
}
}
}
viewFactory and *Class attributes are mutually exclusive — use one or the other. viewFactory takes precedence when both are provided.
<custom-view> without checking the platform — wrap in Device.isAndroid() / Device.isIOS() etc. if not all platforms are supported_deps in BUILD.bazelandroidClass — must match the Kotlin/Java package exactly