How to change static css file on API response in ReactJS - node.js

In my project i want to change the background-color and font of text. Both the properties are written in css file.
Project structure is:
|-myProject
|--public
|--src
|--package.json
All my css is written in public directory, and i have an api which give response of background-color and font. Now i want to change the properties background-color and font in css files according to api response.

Instead of trying to modify the base stylesheets, why not set these particular properties using the elements’ style attributes:
const divStyle = {
backgroundColor: /* Some color */,
fontFamily: /* Some font stack */,
};
function HelloWorldComponent() {
return <div style={ divStyle }>Hello World!</div>;
}
(adapted from the React docs)

I think the best way to do this would be to use inline style on the elements you want to change.
On api response -> set
const yourVar={
backgroundColor:##,
fontFamily:##
};

I believe that the answer from MTCoster is the best approach. depending on the structure of your app you could use the new Context API to make some sort of theme provider, so that you could pass custom styles that could be stored on your application state and that is loaded from your backend API. there are some tools that could help you integrate this feature more easily, like Styled-Components.
with Styled components you culd write something like:
import styled from 'styled-components'
import { YourComponentJSX } from '../somewhere'
// Wrap the component where you need your custom styles
const YourStyledComponent = styled(YourComponentJSX)`
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border-radius: 3px;
/* Color the border and text with theme.main */
// using the short-if to add a default color in case it is not connected to the ThemeProvider
color: ${props => props.theme.main ? props.theme.main : "palevioletred"};
border: 2px solid ${props => props.theme.main ? props.theme.main : "palevioletred"};
`;
// Define what props.theme will look like
const theme = {
main: "mediumseagreen"
};
render(
<div>
<ThemeProvider theme={theme}>
<App>
<YourStyledComponent>Themed</YourStyledComponent>
</App>
</ThemeProvider>
</div>
);
This way you could wrap your whole app and use custom styles saved on the app state that have been loaded from the backend and use them on really deeply nested ui components
*The code is a modification from the styled-component docs

Related

Reuse a 'mixin' with Styled Components across different files?

How can I reuse a collection of styles with Styled Components across different files?
With SASS I can define and use a mixin like so:
#mixin section( $radius:4px ) {
border-radius: $radius;
background: white;
}
.box { #include section(); }
With Styled Components you can extend a style, but this means I would need to import that component into every page. This is pretty cumbersome compared to how variables are available everywhere with the ThemeProvider.
https://www.styled-components.com/docs/basics#extending-styles
Just adding on to the answer by #Evanss
You can make the mixin a function (as in OP) by doing:
const theme = {
sectionMixin: (radius) => `border-radius: ${radius};`
}
and then use it like:
const Button = styled.button`
${props => props.theme.sectionMixin('3px')}
`
or simply:
const Button = styled.button`
${({ theme }) => theme.sectionMixin('3px')}
`
You can create a string with multiple CSS rules and pass that to the ThemeProvider.
const theme = {
sectionMixin:
'background: white; border-radius: 5px; border: 1px solid blue;',
}
<ThemeProvider theme={theme}>

Using Material Icons with Styled Components

Just started playing around with Styled Components. Is there a way to style third party icons such as Material Design Icons? This is the code I have so far but obviously it isn't working. Relavant code is below Content component Thanks!
const MaterialIcon = (props) => <i className="material-icons">account_balance</i>;
const Icon = styled(MaterialIcon)`
background-color: green;
font-size: 50px;
`;
const CheckThisOut = props => (
<Wrapper>
<Header>
<h5>{props.title}</h5>
<Icon />
</Header>
<Divider />
<Content>
<p>5% of all participants in this campaign were first time users.</p>
</Content>
</Wrapper>
);
export default CheckThisOut;
For the styled(AnyComp) notation to work AnyComp needs to accept the incoming className prop and attach it to a DOM node.
For your example to work MaterialIcon has to use the passed in className, otherwise the styles are injected but no DOM node is targeted:
const MaterialIcon = (props) => (
<i className={`material-icons ${props.className}`}>account_balance</i>
);
// WORKS 🎉
const Icon = styled(MaterialIcon)`
background-color: green;
font-size: 50px;
`;
See our documentation page about styling any component for more information!
I know this is an old post, but here's another way to write it as a single expression. Using styled components' .attrs() (see docs) for the class name and the CSS ::after selector for the icon name.
const ThumbUp = styled.i.attrs(() => ({ className: "material-icons" }))`
background-color: green;
font-size: 50px;
&:after {
content: "thumb_up";
}
`;
Writing this in a more generic way will allow you to use it for any of the available icons. This makes use of styled component ability to adapt based on props (see styled components docs for more info).
const MaterialIcon = styled.i.attrs(() => ({ className: "material-icons" }))`
background-color: green;
font-size: 50px;
&:after {
content: ${props => props.iconName || "help"};
}
`;
Which you could then use like this:
<MaterialIcon iconName="check" />

"Unknown props" warning on console when attaching additional props

I'm using Styled Components v2.1.1.
The documentation says that to avoid unnecessary wrappers we can use the .attrs constructor. See: https://www.styled-components.com/docs/basics#attaching-additional-props
I've tried to use it but I always receive the following warning in the console:
Warning: Unknown props `margin`, `padding` on <input> tag. Remove these props from the element. For details, see (removed )
in input (created by styled.input)
in styled.input (created by InputContainer)
in div (created by InputContainer)
in InputContainer
I've created a Webpack Bin to show the error: https://www.webpackbin.com/bins/-KpKbVG-Ed0jysHeFVVY
Am I using it in the wrong way or is there an issue?
As it seems, the example provided on the styled components website is not an actual usable example.
Since the attrs function creates attributes for the properties you set, the error is correct in saying that the html <input> tag does not support the attributes margin and padding: MDN - HTML input attributes
The error you're seeing was marked as an issue on the styled-components GitHub.
The actual solution is not to literally use the example given in the styled-components documentation. For the full explanation, please refer to the issue report.
The code example given by one of the contributers on Github is to modify the example as follows:
const getSize = p => p.size || '1em'
const Input = styled.input.attrs({
// we can define static props
type: 'password'
})`
color: palevioletred;
font-size: 1em;
border: 2px solid palevioletred;
border-radius: 3px;
/* here we use the dynamically computed props */
margin: ${getSize};
padding: ${getSize};
`;

Attribute Selectors for styled-componnets

Is it possible to use attribute selectors when using sytled-components?
&:hover, &[active='true']{
transform: translateY(-4px);
box-shadow: 0 7px 16px 0px rgba(255,63,23,0.87),
}
the idea is that then I have the following
<Button active />
Otherwise I have to duplicate the code and it becomes much more uglier.
I would use the css helper and some interpolations to avoid duplicating the code:
import styled, { css } from 'styled-components';
const hoverStyles = css`
transform: translateY(-4px);
box-shadow: 0 7px 16px 0px rgba(255,63,23,0.87);
`;
const Component = styled.div`
// If the component is hovered add the hoveredStyles
&:hover { ${hoverStyles} }
// If the active property is set add the hoverStyles
${props => props.active && hoverStyles}
`
We don't plan to implement any special behaviour with attribute selectors and props like in your code idea. We want to avoid diverging from actual CSS as much as possible to avoid confusion, highlighting/parsing issues etc.
Lots of things you might want to add special magic syntax in the CSS string for are possible with a touch of JavaScript! (see above)

Isolated styled-components with #font-face

I'm using https://github.com/styled-components/styled-components.
I'm trying to work out the best strategy for components that require #font-face. I want to make sure each component is independent of its context, so I'm defining font-family styles on each them. But if I use injectGlobal in multiple components, I get multiple #font-face rules for the same font.
Should I just define the #font-face rules in my ThemeProvider entry-point component and live with the fact that the desired font might not be loaded by the browser?
That's exactly why we made injectGlobal. If you take a look at our docs they say:
We do not encourage the use of this. Use once per app at most, contained in a single file. This is an escape hatch. Only use it for the rare #font-face definition or body styling.
So what I'd do is create a JS file called global-styles.js which contains this code:
// global-styles.js
import { injectGlobal } from 'styled-components';
injectGlobal`
#font-face {
font-family: 'My custom family';
src: url('my-source.ttf');
}
`
As you can see, all we do here is inject some global styling-in this case #font-face. The last thing necessary to make this work is to import this file in your main entry point:
// index.js
import './global-styles.js'
// More stuff here like ReactDOM.render(...)
This will mean your font-face is only injected once, but still all of your components have access to it with font-family: 'My custom family'!
Doing it this way will give you a flash-of-invisible-text (FOIT), but that has nothing to do with styled-components-it'd be the same if you were using vanilla CSS. To get rid of the FOIT requires a more advanced font loading strategy rather than just #font-faceing.
Since this has nothing to do with styled-components, I highly recommend watching these two Front End Center episodes to learn more about how to best do this: "Crafting Web Font Fallbacks" and "The Fastest Webfont Loader in the West"!
And on the other side of the same coin in Chrome:
do not use #font-face inside injectGlobal if using e.g. react-router.
You will get re-paint of all of you app on each newly loaded route.
And this is why:
Same font-files downloaded on each new route.
As soon as you include font-face in a separate .css file - problem solves as stated in the last comment in this github issue.
injectGlobal is deprecated. Use createGlobalStyle
import { createGlobalStyle } from 'styled-components'
export const GlobalStyle = createGlobalStyle`
body {
font-family: 'Muli', sans-serif;
h1 {
font-weight: 800;
font-size: 36px;
p {
font-size: 18px;
}
}
`;
Then you can use it in your App.js:
import { GlobalStyle } from './styles/global'
class App extends Component {
render() {
return (
<ThemeProvider theme={theme}>
<>
<GlobalStyle/>
<Container/>
</>
</ThemeProvider>
)
}
}
I agree
I get reloaded with
import { createGlobalStyle } from 'styled-components';
import { silver } from 'shared-components/themes/colors';
export default createGlobalStyle`
#font-face {
font-family: "Proxima Nova";
font-style: normal;
font-weight: 300;
font-display: swap;
src: url("/static/media/fonts/proxima_nova/ProximaNova_300.otf");
}
and react create app

Resources