Ui: Overwrite default theme constants ?

Created on 7 Oct 2016  路  8Comments  路  Source: shoutem/ui

Hello,

I want to have a custom theme that overwrite some stuff of the default theme shipped with the UI, but i'm struggling to understand how to overwrite the constants.

For example, if i just want to change the BACKGROUND_COLOR of the defaultTheme, i would like to do something like that:

import { getTheme } from '@shoutem/ui';

const Colors = {
  BACKGROUND: '#f7f2ea',
  SCREEN_BACKGROUND: '#f7f2ea'
};

const customTheme = {
  ...getTheme({
    Colors
  })
  //Overwrite some non constant theme stuff here
};


export default customTheme;

But currently this doesn't work, i didn't see any ways to change the constants of the theme other than

  • copy paste the whole theme.js file and take it from here (but this means to merge it on each upgrade of shoutem)
  • overwrite every single part of theming using my constants

Have i missed something ? If not i'll be happy to send over a PR that enables us to overwrite the variables used by theme.js here: https://github.com/shoutem/ui/blob/develop/theme.js#L55

Thanks

Most helpful comment

Hey @tiagostutz somehow I didn't notice your question until @zrumenjak asked me about it earlier today. Yes, all you have asked here is possible with this package, we at Shoutem, do that for our new projects already. The best way to start is to wrap your app with StyleProvider and pass the theme to it. Just be careful, that the style for all components is expected and need to be defined, so I would recommend start by overriding out default theme. For example, if you want the Card component in your theme to have a red background, the best approach would be something like this:

import { getTheme } from @shoutem/ui;
import _ form 'lodash';

const defaultTheme = getTheme();
export default () => {
  return _.merge(getTheme(), {
    'shoutem.ui.Card': {
      backgroundColor: 'red',
    },
  });
}

Here you can find an example of full theme, which is customizable through our backend.
Arno theme example

All 8 comments

You do not need a theme necessarily.
Just knowing the component structure.

For example:
That's how I replace the style of a DropDownMenu button

<DropDownMenu
    options={this.getCompanies()}
    titleProperty={"name"}
    valueProperty={"id"}
    onOptionSelected={this.companySelected.bind(this)}
    style={{
        selectedOption: {
            borderColor: '#ffffff',
            borderWidth: 1,
            paddingTop: 4,
            paddingBottom: 4,
            minWidth: 260,
            marginTop: 20,
            'shoutem.ui.Text': {
                color: '#ffffff',
                borderColor: '#ffffff'
            },
            'shoutem.ui.Icon': {
              color: '#ffffff'
            }
        }
    }}
/>

This should not be the recommended way, but it worked for me.

Yeah you can do that, and for DropDown it makes sense, but for a component like Card. You want to be able to apply your change to all Card component all over the app without having to pass your custom styles to each one.

I'll try to come up with a PR to improve that.

Yes, it should be enough to add a new argument to the theme function in theme.js.

We currently have a function there that doesn't receive any arguments, and just returns the theme object:

const Colors = {
  TITLE: '#222222',
};

export default () => ({
  'shoutem.ui.Title': {
    color: Colors.TITLE,
  },
});

You could change the theme to expect the variables from the outside, and provide a default value in the theme file. Something like this:

export const defaultVariables = {
  titleColor: '#222222',
};

export default (variables = defaultVariables) => ({
  'shoutem.ui.Title': {
    color: variables.titleColor,
  },
});

After that you could provide completely new variables in your custom theme, or only replace some variables by importing the defaults as well:

import { getTheme, themeVariables } from '@shoutem/ui';

const customVariables = {
  backgroundColor: '#f7f2ea',
  screenBackgroundColor: '#f7f2ea',
};

const customTheme = {
  ...getTheme({
    ...themeVariables,
    ...customVariables,
  })

  // Overwrite some non constant theme stuff here
};


export default customTheme;

Would this solve your problem? It would be great if you could implement this, and submit a pull request.

@zrumenjak Thanks for you comment, yeah i'm pretty busy but by end of next week i'll come up with a PR.

Hi!
I'm on a project that needs a "plugable" theme feature. Is this the same thing we are discussing here? I mean, is it already possible to build entire custom themes for shoutem in a structured way? Like we do in Wordpress, Portals and a bunch of web platforms. I know that it is not the same thing, but I'm wondering whether it would be possible to have a themes system where people could build themes in a specified way and them it will be possible choose which theme you would like to use in the React component, using

Hey @tiagostutz somehow I didn't notice your question until @zrumenjak asked me about it earlier today. Yes, all you have asked here is possible with this package, we at Shoutem, do that for our new projects already. The best way to start is to wrap your app with StyleProvider and pass the theme to it. Just be careful, that the style for all components is expected and need to be defined, so I would recommend start by overriding out default theme. For example, if you want the Card component in your theme to have a red background, the best approach would be something like this:

import { getTheme } from @shoutem/ui;
import _ form 'lodash';

const defaultTheme = getTheme();
export default () => {
  return _.merge(getTheme(), {
    'shoutem.ui.Card': {
      backgroundColor: 'red',
    },
  });
}

Here you can find an example of full theme, which is customizable through our backend.
Arno theme example

You do not need a theme necessarily.
Just knowing the component structure.

For example:
That's how I replace the style of a DropDownMenu button

<DropDownMenu
    options={this.getCompanies()}
    titleProperty={"name"}
    valueProperty={"id"}
    onOptionSelected={this.companySelected.bind(this)}
    style={{
        selectedOption: {
            borderColor: '#ffffff',
            borderWidth: 1,
            paddingTop: 4,
            paddingBottom: 4,
            minWidth: 260,
            marginTop: 20,
            'shoutem.ui.Text': {
                color: '#ffffff',
                borderColor: '#ffffff'
            },
            'shoutem.ui.Icon': {
              color: '#ffffff'
            }
        }
    }}
/>

This should not be the recommended way, but it worked for me.

Thank You So much! Worked like charm...

Simple solution how to not override whole theme (w/o any merges):

import { getTheme } from '@shoutem/ui';

const theme = getTheme();
theme['shoutem.ui.TextInput']['.myStyle'] = {
  margin: 10
};
Was this page helpful?
0 / 5 - 0 ratings

Related issues

arudrakalyan picture arudrakalyan  路  9Comments

tonyneel923 picture tonyneel923  路  9Comments

alejandronanez picture alejandronanez  路  9Comments

shukerullah picture shukerullah  路  9Comments

haikov picture haikov  路  4Comments