169

Say I have a component with a render like this:

<View style={jewelStyle}></View>

Where jewelStyle =

  {
    borderRadius: 10,
    backgroundColor: '#FFEFCC',
    width: 20,
    height: 20,
  },

How could I make the background colour dynamic and randomly assigned? I've tried

  {
    borderRadius: 10,
    backgroundColor: getRandomColor(),
    width: 20,
    height: 20,
  },

But this makes all instances of View have the same colour, I want each one to be unique.

Any tips?

22 Answers 22

220

I usually do something along the lines of:

<View style={this.jewelStyle()} />

...

jewelStyle = function(options) {
   return {
     borderRadius: 12,
     background: randomColor(),
   }
 }

Every time View is rendered, a new style object will be instantiated with a random color associated with it. Of course, this means that the colors will change every time the component is re-rendered, which is perhaps not what you want. Instead, you could do something like this:

var myColor = randomColor()
<View style={jewelStyle(myColor)} />

...

jewelStyle = function(myColor) {
   return {
     borderRadius: 10,
     background: myColor,
   }
 }
Sign up to request clarification or add additional context in comments.

4 Comments

This method doesn't use Stylesheets at all. What's the purpose of those declaring Stylesheets with Stylesheet.create() anyway?
@fatuhoku it's nice for when you need to reuse the same style in multiple places
is there much of a perf benefit to using Stylesheet.create?
@DominicTobias Stylesheet.create packs and "send" the style to the native zone only once. Which means that when you're reusing the same style multiple times, or loading the same component multiple times it's gonna reuse the style instead of packing and "sending" again. For example, if you're loading a 3000 styled-rows you'll feel a considerable boost in perf.
81

Yes you can and actually, you should use StyleSheet.create to create your styles.

import React, { Component } from 'react';
import {
    StyleSheet,
    Text,
    View
} from 'react-native';    

class Header extends Component {
    constructor(props){
        super(props);
    }    

    render() {
        const { title, style } = this.props;
        const { header, text } = defaultStyle;
        const combineStyles = StyleSheet.flatten([header, style]);    

        return (
            <View style={ combineStyles }>
                <Text style={ text }>
                    { title }
                </Text>
            </View>
        );
    }
}    

const defaultStyle = StyleSheet.create({
    header: {
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#fff',
        height: 60,
        paddingTop: 15,
        shadowColor: '#000',
        shadowOffset: { width: 0, height: 3 },
        shadowOpacity: 0.4,
        elevation: 2,
        position: 'relative'
    },
    text: {
        color: '#0d4220',
        fontSize: 16
    }
});    

export default Header;

And then:

<Header title="HOME" style={ {backgroundColor: '#10f1f0'} } />

4 Comments

This answer shows a good example where a style is defined in the stylesheet, but can be overridden later in a component
AFAIK using StyleSheet.flatten just throws away any optimization from StyleSheet.create as stated in the docs: "NOTE: Exercise caution as abusing this can tax you in terms of optimizations. IDs enable optimizations through the bridge and memory in general. Refering to style objects directly will deprive you of these optimizations." (facebook.github.io/react-native/docs/stylesheet.html).
I think the method you're looking for is StyleSheet.compose rather than StyleSheet.flatten as it pulls together 2 style objects (or composes them...). I haven't looked into the source to confirm whether there are any benefits to this over simply passing an array of style objects into the style prop, but it should definitely beat flatten as this is actually looking up original style values from the created style objects.
What is the advantage of using flatten.. what if i do like style={[header, style]} ?
41

If you still want to take advantage of StyleSheet.create and also have dynamic styles, try this out:

const Circle = ({initial}) => {


const initial = user.pending ? user.email[0] : user.firstName[0];

    const colorStyles = {
        backgroundColor: randomColor()
    };

    return (
        <View style={[styles.circle, colorStyles]}>
            <Text style={styles.text}>{initial.toUpperCase()}</Text>
        </View>
    );
};

const styles = StyleSheet.create({
    circle: {
        height: 40,
        width: 40,
        borderRadius: 30,
        overflow: 'hidden'
    },
    text: {
        fontSize: 12,
        lineHeight: 40,
        color: '#fff',
        textAlign: 'center'
    }
});

Notice how the style property of the View is set as an array that combines your stylesheet with your dynamic styles.

Comments

31

The easiest is mine:

<TextInput
  style={[
    styles.default,
    this.props.singleSourceOfTruth ?
    { backgroundColor: 'black' } 
    : { backgroundColor: 'white' }
]}/>

2 Comments

I edited posted answer to comply with @Sarahcartenz comment
wonderful, it's indeed great. One can also override a property with this solution, right? the last overrides the previous
19

Had some issue syntactically. This worked for me

<Text style={[styles.textStyle,{color: 'red'}]}> Hello </Text>

const styles = StyleSheet.create({
   textStyle :{
      textAlign: 'center',   
      fontFamily: 'Arial',
      fontSize: 16
  }
  });

1 Comment

Thank you @Yogesh, this is exactly what I am looking for. I want to make use of styles and yet be able to add more to it on things I needed.
6
  import React, { useContext, useMemo } from 'react';
  import { Text, StyleSheet, View } from 'react-native';
  import colors from '../utils/colors';
  import ThemeContext from './../contexts/ThemeContext';

  export default (props) => {
    const { theme } = useContext(ThemeContext);

    // Constructing styles for current theme
    const styles = useMemo(() => createStyles(theme), [theme]);

    return (
      <View style={styles.container}>
        <Text style={styles.label}>{label}</Text>
      </View>
    );
  };

  const createStyles = (theme: AppTheme) =>
    StyleSheet.create({
      container: { width: '100%', position: 'relative', backgroundColor: colors[theme].background },
      label: {
        fontSize: 13,
        fontWeight: 'bold',
      },
    });

colors.ts

export type AppTheme = 'dark' | 'light';

const light: Colors = {
  background: '#FFFFFF',
  onBackground: '#333333',
  gray: '#999999',
  grayLight: '#DDDDDD',
  red: 'red',
};

const dark: Colors = {
  background: '#333333',
  onBackground: '#EEEEEE',
  gray: '#999999',
  grayLight: '#DDDDDD',
  red: 'red',
};

const colors = {
  dark,
  light,
  primary: '#2E9767',
  secondary: '#F6D130',
};

export default colors;

Comments

5

You'll want something like this:

var RandomBgApp = React.createClass({
    render: function() {

        var getRandomColor = function() {
            var letters = '0123456789ABCDEF'.split('');
            var color = '#';
            for (var i = 0; i < 6; i++ ) {
                color += letters[Math.floor(Math.random() * 16)];
            }
            return color;
        };

        var rows = [
            { name: 'row 1'},
            { name: 'row 2'},
            { name: 'row 3'}
        ];

        var rowNodes = rows.map(function(row) {
            return <Text style={{backgroundColor:getRandomColor()}}>{row.name}</Text>
        });

        return (
            <View>
                {rowNodes}
            </View>
        );

    }
});

In this example I take the rows array, containing the data for the rows in the component, and map it into an array of Text components. I use inline styles to call the getRandomColor function every time I create a new Text component.

The issue with your code is that you define the style once and therefore getRandomColor only gets called once - when you define the style.

3 Comments

Hi Colin, thanks for that, but how can I pass in the other style parameters at the same time?
You mean like style={{backgroundColor:getRandomColor(), color: 'black'}}?
Thanks, that will work but I've accepted the other answer as it helps show how you can pass a block of styles through in one go.
4

I know this is extremely late, but for anyone still wondering here's an easy solution.

You could just make an array for the styles :

this.state ={
   color: "#fff"
}

style={[
  styles.jewelstyle, {
  backgroundColor: this.state.BGcolor
}

The second will override any original background color as stated in the stylesheet. Then have a function that changes the color:

generateNewColor(){
  var randomColor = '#'+Math.floor(Math.random()*16777215).toString(16);
  this.setState({BGcolor: randomColor})
}

This will generate a random hex color. Then just call that function whenever and bam, new background color.

Comments

4

Actually, you can write your StyleSheet.create object as a key with function value, it works properly but it has a type issue in TypeScript:

import React from 'react';
import { View, Text, StyleSheet } from 'react-native';

const SomeComponent = ({ bgColor }) => (
  <View style={styles.wrapper(bgColor)}>
    <Text style={styles.text}>3333</Text>
  </View>
);

const styles = StyleSheet.create({
  wrapper: color => ({
    flex: 1,
    backgroundColor: color,
  }),
  text: {
    color: 'red',
  },
});

1 Comment

That code does not work with React 16.13.1. styles.wrapper is not a function Too bad, would have been really cool.
3

Using object spread operator "..." worked for me:

<View style={{...jewelStyle, ...{'backgroundColor': getRandomColor()}}}></View>

Comments

2

Yes, you can make dynamic styles. You can pass values from Components.

First create StyleSheetFactory.js

import { StyleSheet } from "react-native";
export default class StyleSheetFactory {
  static getSheet(backColor) {
    return StyleSheet.create({
      jewelStyle: {
        borderRadius: 10,
        backgroundColor: backColor,
        width: 20,
        height: 20,
      }
    })
  }
}

then use it in your component following way

import React from "react";
import { View } from "react-native";
import StyleSheetFactory from './StyleSheetFactory'
class Main extends React.Component {
  getRandomColor = () => {
    var letters = "0123456789ABCDEF";
    var color = "#";
    for (var i = 0; i < 6; i++) {
      color += letters[Math.floor(Math.random() * 16)];
    }
    return color;
  };

  render() {
    return (
      <View>
        <View
          style={StyleSheetFactory.getSheet(this.getRandomColor()).jewelStyle}
        />
        <View
          style={StyleSheetFactory.getSheet(this.getRandomColor()).jewelStyle}
        />
        <View
          style={StyleSheetFactory.getSheet(this.getRandomColor()).jewelStyle}
        />
      </View>
    );
  }
}

Comments

2

You can do something like this.

In your component:

const getRandomColor = () => {
  // you can use your component props here.
}

<View style={[styles.jewelStyle, {backgroundColor: getRandomColor()}]} />

Create your style using stylesheet:

const styles = StyleSheet.create({
  jewelStyle: {
    backgroundColor: 'red',
  },
});

Comments

2
<View 
 style={[styles.categoryItem,{marginTop: index <= numOfColumns-1 ? 10 : 0   }]}
>                                       

Comments

1

I know there are several answers, but i think the best and most simple is using a state "To change" is the state purpose.

export default class App extends Component {
    constructor(props) {
      super(props);
      this.state = {
          style: {
              backgroundColor: "white"
          }
      };
    }
    onPress = function() {
      this.setState({style: {backgroundColor: "red"}});
    }
    render() {
       return (
          ...
          <View style={this.state.style}></View>
          ...
       )
    }

}

Comments

1

You can bind state value directly to style object. Here is an example:

class Timer extends Component{
 constructor(props){
 super(props);
 this.state = {timer: 0, color: '#FF0000'};
 setInterval(() => {
   this.setState({timer: this.state.timer + 1, color: this.state.timer % 2 == 0 ? '#FF0000' : '#0000FF'});
 }, 1000);
}

render(){
 return (
   <View>

    <Text>Timer:</Text>
    <Text style={{backgroundColor: this.state.color}}>{this.state.timer}</Text>
  </View>
 );
 }
}

Comments

1

If you are using a screen with filters for example, and you want to set the background of the filter regarding if it was selected or not, you can do:

<TouchableOpacity style={this.props.venueFilters.includes('Bar')?styles.filterBtnActive:styles.filterBtn} onPress={()=>this.setFilter('Bar')}>
<Text numberOfLines={1}>
Bar
</Text>
</TouchableOpacity>

On which set filter is:

setVenueFilter(filter){
  var filters = this.props.venueFilters;
  filters.push(filter);
  console.log(filters.includes('Bar'), "Inclui Bar");
  this.setState(previousState => {
    return { updateFilter: !previousState.updateFilter };
  });
  this.props.setVenueFilter(filters);
}

PS: the function this.props.setVenueFilter(filters) is a redux action, and this.props.venueFilters is a redux state.

Comments

1

If you are following the functional approach of React-Native, you can use a package called dynamic-styles that tries to solve exactly your problem.

// -- theme.js ------------------------------------------------------

// Initialization of a StyleSheet instance called 'styleSheet'
export const styleSheet = createStyleSheet({
    theme: /* optional theme */
});



// -- MyComponent.js -----------------------------------------------

// Create dynamic stylesheet that has access 
// to the previously specified theme and parameters
const useStyles = styleSheet.create(({theme, params}) => ({
    root: /* Dynamic Styles */,
    button: /* Dynamic Styles */,
    text: /* Dynamic Styles */,
}));

const MyComponent = (props) => {
    // Access dynamic styles using the created 'useStyles()' hook 
    // and specify the corresponding parameters
    const { styles } = useStyles({ color: props.color, fontSize: 10 });
    
    return (
      <div className={styles.root}>
          {/* */}
      </div>
    );
}

It basically allows you to create dynamic stylesheets and link them to functional Components using the React hook pattern.

-> Codesandbox

Comments

0

In case someone needs to apply conditions

 selectedMenuUI = function(value) {
       if(value==this.state.selectedMenu){
           return {
                flexDirection: 'row',
                alignItems: 'center',
                paddingHorizontal: 20,
                paddingVertical: 10,
                backgroundColor: 'rgba(255,255,255,0.3)', 
                borderRadius: 5
           }  
       } 
       return {
            flexDirection: 'row',
            alignItems: 'center',
            paddingHorizontal: 20,
            paddingVertical: 10
       }
    }

Comments

0

Here is what worked for me:

render() {
  const { styleValue } = this.props;
  const dynamicStyleUpdatedFromProps = {
    height: styleValue,
    width: styleValue,
    borderRadius: styleValue,
  }

  return (
    <View style={{ ...styles.staticStyleCreatedFromStyleSheet, ...dynamicStyleUpdatedFromProps }} />
  );
}

For some reason, this was the only way that mine would update properly.

Comments

0

you can use styled-components for react native it will provide you dynamic styling just like emotion or styled-components for web.

Comments

0

For something relatively simple, you can use this approach:

StyleSheet.create({
    item: props.selectedId === item.id ? {
        backgroundColor: 'red',
    }: null
});

2 Comments

Can you explain what the specific options you included like selectedId and the itemId? Are they apart of some other code you didn't copy over?
selectedId and item are both props. But it could be anything state, variables, etc.
0

In React Native, you can create dynamic styles using functions that return style objects. This allows you to change the styles of your components based on certain conditions.

Here's an example:

import { StyleSheet } from 'react-native'
import { Color } from 'theme/theme'
import { StyleSheetType, StylesFunctionProps } from 'components/MyComponent/types'

export const styles: StylesFunctionProps = ({ isDisabled, focused }) =>
  StyleSheet.create<StyleSheetType>({
    primary: {
      backgroundColor: isDisabled ? Color.Gray : Color.Primary,
      borderColor: isDisabled ? Color.Gray : Color.Primary,
    },
    secondary: {
      backgroundColor: 'transparent',
      borderColor: isDisabled ? Color.Red : Color.Secondary,
    },
    // ... rest of the styles
  })

Note: StyleSheetType must contain all the StyleSheet styles object keys such as:

type StyleSheetType = {
  primary: ViewStyle
  secondary: ViewStyle
  anotherStyle: TextStyle
  // ... rest of the styles keys
}

StylesProps are props you want to pass to the StyleSheet

export type StylesProps = {
  isLoading?: boolean
  isDisabled?: boolean
/// ... rest

}

Also StyleFunctionProps is:

export type StylesFunctionProps = (props: StylesProps) => StyleSheetType

Usage:

import styles from './styles';

const MyComponent = () = >{
  const isLoading = /* some condition */;
  const isDisabled = /* some condition */;

  const dynamicStyles = styles({ isDisabled, isLoading });

  return (
    <View style={dynamicStyles.primary}>
      {/* rest of the component */}
    </View>
  );
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.