Creating a mapping for a custom component allows you to leverage the Eva Design System’s theming and styling capabilities in your own components. This guide will walk you through building a custom CircleButton component with full Eva integration.
Prerequisites
For the best developer experience, install and configure the @babel/plugin-proposal-decorators module.
Install Babel Plugin
npm install --save-dev @babel/plugin-proposal-decorators
# or
yarn add -D @babel/plugin-proposal-decorators
Configure Babel
Update your babel.config.js: module . exports = {
// Your existing configuration
plugins: [
[ "@babel/plugin-proposal-decorators" , { "legacy" : true }]
]
};
Creating the Component
Step 1: Component Boilerplate
Create your component using the @styled decorator:
import React from 'react' ;
import { TouchableOpacity } from 'react-native' ;
import { styled } from '@ui-kitten/components' ;
@ styled ( 'CircleButton' )
export class CircleButton extends React . Component {
render () {
const { eva , style , ... restProps } = this . props ;
return (
< TouchableOpacity style = { [ eva . style , style ] } { ... restProps } />
);
}
}
The @styled decorator injects the eva prop, which contains the computed styles from your mapping.
Step 2: Create the Mapping
Create a mapping.json file with the initial configuration:
{
"components" : {
"CircleButton" : {
"meta" : {
"parameters" : {},
"variantGroups" : {},
"states" : {},
"appearances" : {
"filled" : {
"default" : true
}
}
},
"appearances" : {
"filled" : {
"mapping" : {}
}
}
}
}
}
Step 3: Apply the Mapping
Pass your custom mapping to ApplicationProvider:
import React from 'react' ;
import * as eva from '@eva-design/eva' ;
import { ApplicationProvider , Layout } from '@ui-kitten/components' ;
import { default as mapping } from './mapping.json' ;
import { CircleButton } from './CircleButton' ;
export default () => (
< ApplicationProvider
{ ... eva }
customMapping = { mapping }
theme = { eva . light } >
< Layout style = { { padding: 64 , alignItems: 'center' } } >
< CircleButton />
</ Layout >
</ ApplicationProvider >
) ;
If you’re using @ui-kitten/metro-config, custom mappings are applied automatically. Check your metro.config.js to verify.
Defining Component Parameters
Register and Apply Parameters
Define the visual properties of your component:
{
"components" : {
"CircleButton" : {
"meta" : {
"parameters" : {
"width" : {
"type" : "number"
},
"height" : {
"type" : "number"
},
"borderRadius" : {
"type" : "number"
},
"backgroundColor" : {
"type" : "string"
}
},
"variantGroups" : {},
"states" : {},
"appearances" : {
"filled" : {
"default" : true
}
}
},
"appearances" : {
"filled" : {
"mapping" : {
"width" : 64 ,
"height" : 64 ,
"borderRadius" : 32 ,
"backgroundColor" : "color-primary-default"
}
}
}
}
}
}
The backgroundColor uses color-primary-default, which references the theme variable. This makes your component automatically adapt to theme changes.
Adding Variants
Variants allow components to have different visual styles:
{
"components" : {
"CircleButton" : {
"meta" : {
"parameters" : {
// ... previous parameters
},
"variantGroups" : {
"shape" : {
"rounded" : {
"default" : false
}
}
},
"appearances" : {
"filled" : {
"default" : true
}
}
},
"appearances" : {
"filled" : {
"mapping" : {
"width" : 64 ,
"height" : 64 ,
"borderRadius" : 32 ,
"backgroundColor" : "color-primary-default"
},
"variantGroups" : {
"shape" : {
"rounded" : {
"borderRadius" : 16
}
}
}
}
}
}
}
}
Now you can use the variant:
< CircleButton shape = 'rounded' />
< CircleButton />
// Renders as a circle with borderRadius: 32
< CircleButton shape = 'rounded' />
// Renders with borderRadius: 16
Implementing States
States allow components to change appearance based on user interaction:
Update the Mapping
{
"components" : {
"CircleButton" : {
"meta" : {
"parameters" : {
// ... previous parameters
},
"variantGroups" : {
// ... previous variants
},
"states" : {
"active" : {
"default" : false
}
},
"appearances" : {
"filled" : {
"default" : true
}
}
},
"appearances" : {
"filled" : {
"mapping" : {
"width" : 64 ,
"height" : 64 ,
"borderRadius" : 32 ,
"backgroundColor" : "color-primary-default" ,
"state" : {
"active" : {
"backgroundColor" : "color-primary-active"
}
}
},
"variantGroups" : {
// ... previous variants
}
}
}
}
}
}
Dispatch States from Component
import React from 'react' ;
import { TouchableOpacity } from 'react-native' ;
import { styled , Interaction } from '@ui-kitten/components' ;
@ styled ( 'CircleButton' )
export class CircleButton extends React . Component {
onPressIn = () => {
// Dispatch active state
this . props . eva . dispatch ([ Interaction . ACTIVE ]);
};
onPressOut = () => {
// Return to default state
this . props . eva . dispatch ([]);
};
render () {
const { eva , style , ... restProps } = this . props ;
return (
< TouchableOpacity
{ ... restProps }
activeOpacity = { 1.0 }
style = { [ eva . style , style ] }
onPressIn = { this . onPressIn }
onPressOut = { this . onPressOut }
/>
);
}
}
The dispatch function is provided by the @styled decorator and allows you to request different style configurations based on component state.
Available Interactions
The Eva Design System supports several interaction states:
import { Interaction } from '@ui-kitten/components' ;
// Available interactions:
Interaction . HOVER
Interaction . ACTIVE
Interaction . FOCUSED
Interaction . INDETERMINATE
Interaction . VISIBLE
Complete Example
Here’s a complete custom component with multiple features:
import React from 'react' ;
import { TouchableOpacity , Text } from 'react-native' ;
import { styled , Interaction } from '@ui-kitten/components' ;
interface CircleButtonProps {
shape ?: 'circle' | 'rounded' ;
status ?: 'primary' | 'success' | 'danger' ;
children ?: React . ReactNode ;
}
@ styled ( 'CircleButton' )
export class CircleButton extends React . Component < CircleButtonProps > {
onPressIn = () => {
this . props . eva . dispatch ([ Interaction . ACTIVE ]);
};
onPressOut = () => {
this . props . eva . dispatch ([]);
};
render () {
const { eva , style , children , ... restProps } = this . props ;
return (
< TouchableOpacity
{ ... restProps }
activeOpacity = { 1.0 }
style = { [ eva . style , style ] }
onPressIn = { this . onPressIn }
onPressOut = { this . onPressOut }
>
{ children }
</ TouchableOpacity >
);
}
}
Mapping Structure Reference
Best Practices
Use Theme Variables
Reference theme variables (e.g., color-primary-default) instead of hardcoded colors to ensure your component adapts to theme changes.
Define Default Values
Always specify which appearance and variants are default in the meta section.
Leverage State System
Use the Eva state system for interactive components instead of managing state manually.
Follow Naming Conventions
Use camelCase for parameters and kebab-case for variant values to maintain consistency.
Test All Combinations
Ensure all variant and state combinations render correctly.
Next Steps
Customize Mapping Learn how to customize existing component mappings
Glossary Understand Eva Design System terminology