Skip to main content

Styles

Styles are React Native styles: plain objects, StyleSheet.create, arrays that flatten. The engine reads a defined set of properties and ignores the rest, and the package's types declare exactly that set, so a property that typechecks is one that does something.

const styles = StyleSheet.create({
card: {flex: 1, padding: 16, borderRadius: 12, backgroundColor: '#0d2035'},
title: {color: '#e6edf5', fontSize: 20, fontWeight: '700'},
});

<View
style={[styles.card, active && {borderColor: '#38bdf8', borderWidth: 1}]}
/>;

Layout​

The flexbox properties: width, height, minWidth, minHeight, maxWidth, maxHeight, aspectRatio; flex, flexGrow, flexShrink, flexBasis, flexDirection (including the -reverse values), flexWrap (including wrap-reverse); justifyContent, alignItems, alignSelf, alignContent; margin and padding with their Top/Right/Bottom/Left/ Horizontal/Vertical variants; gap, rowGap, columnGap; position (relative or absolute) with top, left, right, bottom; display (flex or none), overflow (visible, hidden, scroll) and zIndex.

Percentages. width, height, flexBasis and the four insets accept a '50%' string. A percentage on width/height measures the parent's content box; on left/right the containing block's width; on top/bottom its height. Margins, padding, min/max sizes and borders take pixels only.

The Layout page explains the solver and where it differs from a phone.

Paint​

PropertyNotes
backgroundColorAnimatable. Flow B: the alpha of a View background is ignored (opaque fill); pre-mix a tint
opacity0 to 1, animatable. Below 1 the subtree composites through offscreen scratch; keep such nodes small
pointerEvents'auto' | 'none' | 'box-none' | 'box-only'. A style entry here (React Native also allows it as a prop), because that is what the engine reads

Borders​

borderRadius and the four per-corner radii; borderWidth and the four per-side widths; borderColor and the four per-side colours; borderStyle (solid, dashed, dotted). Radius edges are anti-aliased (ERUI_BORDER_AA). On an Image the radii clip the bitmap to the same rounded edge; an Image draws no border.

Transform​

style={{transform: [{rotate: '45deg'}, {scale: pulse}], transformOrigin: [0.5, 1]}}

transform is an array of {scale}, {scaleX}, {scaleY}, {translateX}, {translateY}, {rotate}, {rotateX}, {rotateY}, {rotateZ} or {perspective}. Rotations are CSS angle strings ('45deg', '0.5rad'). Every axis except perspective can be an Animated.Value; scale binds both axes at once. transformOrigin is a fractional [x, y] pivot in 0 to 1, default the centre. rotateX/rotateY/perspective need a build with ERUI_3D_TRANSFORMS. Flow B takes a transform only as Animated.Values on scale, scaleX, scaleY, translateX, translateY or rotate/rotateZ; a static transform, or a static entry beside an animated one, is rejected.

A transformed subtree renders through the transform scratch buffer, whose size caps the largest node that can rotate or scale; see Memory.

Shadow​

shadowColor, shadowOffset ({width, height}), shadowOpacity, shadowRadius and elevation, rendered only in a build with ERUI_SHADOWS and a shadowOpacity above 0. Shadows are a two-pass blur through scratch memory; the small-board examples build without them.

Text​

On Text (and TextInput, ActivityIndicator): color (animatable), fontSize, fontFamily (a baked font's family name), fontWeight (600 and up, or 'bold', selects the bold face; the engine carries no other weights), fontStyle ('italic' is a synthetic slant), textAlign, textDecorationLine (underline, line-through), lineHeight, letterSpacing.

Only baked font sizes exist on the device; another size snaps to the nearest baked one. See Assets. Flow B: see what it does not accept.

Two components add a property of their own: Modal reads backdropColor for its scrim, and TextInput reads cursorColor for the caret.

Colours​

Flow A parses #rgb, #rrggbb, #rrggbbaa, rgb()/rgba() and the names transparent, black, white, red, green, blue, gray/grey, yellow, cyan, magenta and orange, in any case and with their CSS values (green is #008000). Flow B accepts #rgb, #rrggbb, #rrggbbaa and the same names, and a state-driven color must be a literal or a ternary of literals. Neither flow parses #rgba in a style.

StyleSheet​

StyleSheet.create(styles) returns its argument; it exists for parity and for the Flow B compiler, which treats a StyleSheet.create reference as the static layer of a style. StyleSheet.flatten merges an array into one object. StyleSheet.hairlineWidth is 1 and StyleSheet.absoluteFill is {position: 'absolute', top: 0, left: 0, right: 0, bottom: 0}; Flow B cannot reference either, so write the values out.

Flow B: a style object holding any state-driven value may contain only keys the compiler can update at runtime (colors, opacity, sizes, margins, padding, the flex alignment enums, position, display). Keep the rest in StyleSheet.create and overlay the dynamic part: style={[styles.btn, {backgroundColor: on ? A : B}]}, with the static layer a StyleSheet.create reference rather than an inline object.

Flow B​

The AOT compiler rejects a style key it cannot lower. Beyond the limits above, Flow B does not accept aspectRatio, flexWrap, alignContent, overflow, pointerEvents, borderStyle, the per-side border widths and colors, the shadow keys and elevation, transformOrigin, fontFamily, fontStyle, textAlign or textDecorationLine.

It also rejects a key the engine does not draw on that element, which Flow A ignores without a word. The layout keys and transform work everywhere. backgroundColor, the borders and opacity work on View, ScrollView, Pressable, TouchableOpacity and Modal, and on TextInput without the per-corner radii. borderRadius, the per-corner radii and opacity work on Image. color, fontSize, fontWeight, lineHeight, letterSpacing and opacity work on Text; TextInput takes color and fontSize, and ActivityIndicator takes color as its tint. A nested <Text> span takes color, fontSize, fontWeight and letterSpacing only.

Animated values in styles​

An Animated.Value can sit directly in any transform axis on any element, in opacity on a View, ScrollView, Pressable, Modal, Text, Image or TextInput, and in a Dial's value/valueStart. backgroundColor on a View, ScrollView, Pressable or Modal and color on a Text take an interpolation onto colors: v.interpolate({inputRange: [0, 1], outputRange: ['#000', '#fff']}). The engine animates nothing else, so Flow B rejects it. The Animated.* wrappers are pass-through. The engine binds the value to the property and drives it natively; no JavaScript runs per frame. See Animated.