Skip to main content
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.
1

Install Babel Plugin

npm install --save-dev @babel/plugin-proposal-decorators
# or
yarn add -D @babel/plugin-proposal-decorators
2

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

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

Defines the component’s available configurations:
  • parameters: Style properties the component can use
  • variantGroups: Logical groupings of style variations
  • states: Interaction states the component supports
  • appearances: High-level visual styles

Best Practices

1

Use Theme Variables

Reference theme variables (e.g., color-primary-default) instead of hardcoded colors to ensure your component adapts to theme changes.
2

Define Default Values

Always specify which appearance and variants are default in the meta section.
3

Leverage State System

Use the Eva state system for interactive components instead of managing state manually.
4

Follow Naming Conventions

Use camelCase for parameters and kebab-case for variant values to maintain consistency.
5

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

Build docs developers (and LLMs) love