When using ordinary CSS if you want to style your place holder you use these css selectors :
::-webkit-input-placeholder {
color: red;
}
But I can't figure out how to apply these type of styles in react inline styles.
Simply give your "input" tag an "id" or a "class" and put your css style in App.css inside src. e.g
//App.css or external stylesheet
#inputID::placeholder {
color: #ff0000;
opacity: 1;
}
//your jsx code
<input type="text" id="inputID" placeholder="Your text here" />
That actually worked for me.
You can't use ::-webkit-inline-placeholder inline.
It is a pseudo-element that (much like e.g. :hover) can only be used in your stylesheet:
The non-standard proprietary ::-webkit-input-placeholder pseudo-element represents the placeholder text of a form element.
Source
Instead, assign a class to the React component via the className property and apply the style to this class.
You could try to use radium
var Radium = require('radium');
var React = require('react');
var color = require('color');
#Radium
class Button extends React.Component {
static propTypes = {
kind: React.PropTypes.oneOf(['primary', 'warning']).isRequired
};
render() {
// Radium extends the style attribute to accept an array. It will merge
// the styles in order. We use this feature here to apply the primary
// or warning styles depending on the value of the `kind` prop. Since its
// all just JavaScript, you can use whatever logic you want to decide which
// styles are applied (props, state, context, etc).
return (
<button
style={[
styles.base,
styles[this.props.kind]
]}>
{this.props.children}
</button>
);
}
}
// You can create your style objects dynamically or share them for
// every instance of the component.
var styles = {
base: {
color: '#fff',
// Adding interactive state couldn't be easier! Add a special key to your
// style object (:hover, :focus, :active, or #media) with the additional rules.
':hover': {
background: color('#0074d9').lighten(0.2).hexString()
},
'::-webkit-input-placeholder' {
color: red;
}
},
primary: {
background: '#0074D9'
},
warning: {
background: '#FF4136'
}
};
Do not use ::-webkit-inline-placeholder inline and Radium for one placeholder.
I suggest go to your index.css
input.yourclassname::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */
color: white;
opacity: 1; /* Firefox */
}
My approach is to simply apply different styles to the entire <input /> component based on whether or not the value is empty. No need to install a new dependency, and no need to use a stylesheet which seems to be the point of the original question.
var inputStyles = {
border: '1px solid #cbcbcb',
color: '#525252',
};
var placeholderStyles = {
...inputStyles,
color: '#999999',
};
<input
type="text"
placeholder="enter text here"
value={myValue}
style={myValue ? inputStyles : placeholderStyles}
/>
For me, I use Radium's Style component. Here's what you can do in ES6 syntax:
import React, { Component } from 'react'
import Radium, { Style } from 'radium'
class Form extends Component {
render() {
return (<div>
<Style scopeSelector='.myClass' rules={{
'::-webkit-input-placeholder': {
color: '#929498'
}}} />
<input className='myClass' type='text' placeholder='type here' />
</div>
}
}
export default Radium(Form)
Use Template Literals i.e. Backward quotes(``) for adding your pseudo-element.
const inputFieldStyle = `
.inputField::-webkit-input-placeholder{
color: red;
}`
Using class is important thing so make sure you used class before pseudo-element.
Then you can use tag where you pass above style like below:
const reactFunctionalComponent = (props) => {
...
return(
<>
<style>
{inputFieldStyle}
</style>
...
</>
)
}
Here is a method that provides pseudo selector functionality in React, without relying on a third party library, in about 20 lines of code.
This is an extension of RohitSawai's answer that injects a <style> tag, but in a more encapsulated and reusable fashion.
Define this function once in your project:
/** Returns a unique className and injectStyle function that can be used to
style pseudo elements. Apply the className to the desired element and render
injectStyle() nearby. The pseudo selector, e.g. ::-webkit-input-placeholder,
will be appended to the unique className, styling a pseudo element directly,
or a descendant pseudo element, as determined by the selector. */
const pseudo = (pseudoSelector, style) => {
const className = `pseudo-${Math.floor(Math.random() * 1000000)}`
// simple encoding of style dictionary to CSS
// for simplicity, assumes that keys are already in slug case and units have
// been added, unlike React.CSSProperties
const styleCSS =
'{' +
Object.entries(style)
.map(([name, value]) => `${name}: ${value};`)
.join('') +
'}'
return {
className,
injectStyle: () => (
<style>
{`.${className}${pseudoSelector} ${styleCSS}`}
</style>
)
}
}
And use it like this:
const MyComponent = () => {
const placeholder = pseudo('::-webkit-input-placeholder', { color: 'red' })
return (<div>
{placeholder.injectStyle()}
<input className={placeholder.className} placeholder="This placeholder is red" />
</div>)
}
Related
I appreciate this may be a little basic here, but I'm relatively new to React and am testing the waters with various ways of applying on-the-fly styling rather than creating separate stylesheets and importing them.
I'm trying to experiment adding styles to three different elements - one via inline styles, another via a style tag, and another via a style variable - where only the inline style seems to work.
Here is my code with all 3 elements:
import React from 'react'
const App = () => {
render {
const testOneStyle = {
color: "red",
fontWeight: "bold"
};
return (
<div>
<span style={testOneStyle} className="test-one">test 1</span>
<span className="test-two">test 2</span>
<style>
.test-two {
color: red;
font-weight: bold
}
</style>
<span style={{color: "red"}} className="test-three">test 3</span>
</div>
)
}
}
export default App
Firstly, does the variable style (i.e. here) only work with class components rather than functional components?
And can someone explain why this is not rendering and how to render and apply the styles?
Thank you for any advice. Here is a StackBlitz demo: https://stackblitz.com/edit/react-tjukup
Unfortunately, <style> tags don't work in JSX the way they do in html. You are going to have to parse the the string appropriately yourself, since JSX is just javascript with syntactical sugar to convert into React.createElement() function with the right parameters. So you want to generally avoid style and head tags in JSX, but if you do, you want to use it like:
<style>
{"\
.test-two {\
color: red;\
font-weight: bold;\
}\
"}
</style>
EDIT
Also, to answer your question "does the variable style only work with class components rather than functional components?", no. The prop style is a JSX prop and works regardless of what kind of component you are using.
EDIT
And the reason why your component is not rendering, is because render() is a function that is only used in class based components. In a functional component you just directly return the JSX.
import React from "react";
const App = () => {
const testOneStyle = {
color: "red",
fontWeight: "bold"
};
return (
<div>
<span style={testOneStyle} className="test-one">
test 1 - fails
</span>
<span className="test-two">test 2 - fails</span>
<style>
{`
.test-two {
color: red;
font-weight: bold
}
`}
</style>
<span style={{ color: "red" }} className="test-three">
test 3 - works
</span>
</div>
);
};
export default App;
EDIT
As you may have observed in the snippet I have provided, you can also use strings with "`" to make it easier to enter strings in JSX
I hope this may helps you
import React from 'react'
const App = () => {
const testOneStyle = {
color: "blue",
fontWeight: "bold"
};
return (
<div>
<span style={testOneStyle} className="test-one">
test 1 - fails
</span>
<span className="test-two">
test 2 - fails
</span>
<style>
{
`.test-two {
color: green;
font-weight: bold
}`
}
</style>
<span style={{color: "red"}} className="test-three">
test 3 - works
</span>
</div>
)
}
export default App
Explaination:
You are using functional component
Class component require render method to return a JSX. Functional component can directly return JSX.
you can add style tag in your JSX but the context inside need to be string.
I have a simple message board with nested comments built in React. I'm trying to add a favorite button (just a button that toggles filled/unfilled contingent on its boolean value). Every tutorial I find involves making a new component, but I'd like to include this in my primary app code (using a hook/useState).
I've tried some various CSS stuff like active, etc. I'm rusty with CSS and a bit lost using it on JSX. Ideally, it'd be a star button that fills/unfills, but I want to figure out the simple basics here first.
function Toggle(props) {
const [toggleState, setToggleState] = useState(false);
function toggle() {
setToggleState(toggleState === false? true : false);
}
return (
<div {...props}>
<Button
className={`switch ${toggleState}`}
onClick={toggle}>
Favorite
</Button>
</div>
)
}
Toggle=styled(Toggle)`
//dunno what to put here
The button shows up just fine but nothing I try in the style will make it toggle colors (or filled/unfilled) on click. How can I do this?
First of all this syntax is more readable
function toggle() {
setToggleState(!toggleState);
}
then you can use this to change the class of your button
className={`switch ${toggleState ? "some_class" : "some_other_class"}`}
If you use styled-components, you can customize Button directly. In Tagged templates, switch styles according to prop.
Demo
const Button = styled(Icon)`
color: ${props => (props.filled ? 'pink' : 'transparent')};
-webkit-text-stroke: 2px pink;
overflow: hidden;
margin: 0 0.5em;
cursor: pointer;
`
function Toggle(props) {
const [toggleState, setToggleState] = useState(false)
function toggle() {
setToggleState(toggleState => !toggleState)
}
return (
<Button filled={toggleState} onClick={toggle}>
favorite
</Button>
)
}
Adapting based on props
Following your code:
const StyledToggle=styled(Toggle)`
&.true {
//true styles
}
&.false {
//false styles
}
`;
As you are using css in js you could also pass the state as a prop to the component and read it inside the tagged template:
return (
<div {...props}>
<Button
toggleState={toggleState}
onClick={toggle}>
Favorite
</Button>
</div>
)
}
const StyledToggle = styled(Toggle)`
font-weight: ${({toggleState}) => toggleState && "bold"};
`;
Dear genius StackOverflowians,
I am trying to write an app where users can configure questions and answers, along with defining help text for each question. I'm writing this in typescript React - which is handy when you want to define types of answers for questions.
I want to have a button next to the question that shows/hides a styled document. The button looks and works great, but the document that is hidden/shown doesn't get the generated style class that ought to be associated with it.
Here is the functional component to display the help document:
let HelpTextBody = function(props: { helpDocument: DocumentationStore }) {
return (
<div>
{props.helpDocument.toReallySimple().map(tok => {
return React.createElement(tok.tag, null, tok.content);
})}
</div>
);
};
tok comes from a custom class DocumentationStore that is pretty much a wrapper around markdown-it, a handy js library for working with md files, which I would like my users to write their helptext in (and store it that way).
So I do this (in a different module for DocumentationStore class):
toReallySimple(): MdJson[] {
let bigParsed = this.md_.parse(this.Text, null).filter(
t => return t.type == "inline" || t.type.indexOf("open") > 0
});
Later on, I style HelpTextBody with:
const StyledHelpDocument = styled(HelpTextBody)`
background-color: lightslategray;
`;
Keeping it simple now so I can just see if it's working...
I then include it in a component with the button that I export:
class HelpText extends React.Component<helpProps, helpState> {
constructor(props: helpProps) {
super(props);
this.state = {
hidden: true
};
}
swapHidden() {
this.setState({
hidden: !this.state.hidden
});
}
render() {
if (this.state.hidden) {
return (
<span>
<StyledButton
itemScope={this.state.hidden}
onClick={() => this.swapHidden()}
>
Need Help?
</StyledButton>
</span>
);
} else {
return (
<span>
<StyledButton onClick={() => this.swapHidden()}>
Hide Help
</StyledButton>
<StyledHelpDocument helpDocument={this.props.helpDocument} />
</span>
);
}
}
So I webpack it all and get stuff into the browser, and what I get back is this style tag (after clicking the button), which looks right:
<style data-styled-components="">
/* sc-component-id: sc-bdVaJa */
.sc-bdVaJa {} .gscXTZ{background:red;color:white;font-size:1em;margin:1em;padding:0.25em 1em;border:2px solid red;border-radius:3px;}.iwtdKP{background:white;color:red;font-size:1em;margin:1em;padding:0.25em 1em;border:2px solid red;border-radius:3px;}
/* sc-component-id: sc-bwzfXH */
.sc-bwzfXH {} .hAvMqj{background-color:lightslategray;}</style>
But my html for the document is missing the reference to the class (.hAvMqj I guess?)
<span>
<button class="sc-bdVaJa iwtdKP">Hide Help</button>
<div><p>Here the text is grey</p></div>
<!-- ^This^ is the StyledHelpDocument... no class!-->
</span>
So where am I going wrong? I don't understand why it generates the style, and the component's HTML renders... but the class isn't applied to the component! What do you think?
Your styled-components class isn't being applied because you're styling a custom component, but you haven't included className as a prop. Add className as an optional prop in the component you're styling, and also be sure to apply className somewhere in the render method for that component. For your case, it should be added like so:
let HelpTextBody = function(props: { helpDocument: DocumentationStore, className: string }) {
return (
<div className={props.className}>
{props.helpDocument.toReallySimple().map(tok => {
return React.createElement(tok.tag, null, tok.content);
})}
</div>
);
};
In App.css, I have
.theme {
color: green;
}
And I have className="theme" scattered in multiple components.
Is there a way to change the theme color from green to blue on an event?
If not, how should I design my code?
Well, You can create 2 classes named .blue-theme and .green-theme
Whenever, some event occurs,
onClick = (themeCol) => {
this.setState({theme:thmeCol})
}
render(){
return(
<button onClick={()=>onClick('blue-theme')}>Blue theme</button>
<button onClick={()=>onClick('green-theme')}>Green theme</button>
<div className={this.state.theme}> Sample </div>
)
}
You can pass the value of theme.
you can try
const themeClass = "";
if (event-as-wanted){
themeClass="theme";
}
className={themeClass}
also you can use style insted of className in same file
const theme ={
color: '';
};
style={theme}
and change it with events like
if (event-as-wanted){
theme.color = "green";
}
You can conditionally render the <style/> tag to override style definition for the class in the whole document.
class App extends React.Component {
state = {
red: true,
}
render() {
return (
<div>
<div className="foo">Foo</div>
<button onClick={() => this.setState({ red: !this.state.red })}>
Toggle Red
</button>
{this.state.red && <style>{".foo { color: red }"}</style>}
</div>
);
}
}
Keep in mind that inside JSX tags, curly brackets will be picked up by the interpreter and may break the parser. To avoid that, you should put your CSS inside a string like in the example above.
Adding a <style/> tag to CSS document will override any equally specific CSS rules that came before that. Once the condition is no longer met, the style tag will be removed and the original styling will be restored.
in react.js just set the state of color to whatever and on a click event toggle the color
class App extends React.Component {
constructor(props) {
super(props);
this.state = {color: green};
this.changeColor = this.changeColor.bind(this);
}
changeColor() {
const newcolor = this.state.color == green ? blue : green;
this.setState({ color: newcolor});
}
render() {
return (
<div class="theme" style={{color: this.statecolor}}>
<button onClick={this.changeColor}>
</button>
//put all html withing the parent DOM of element with class theme accordingly or it wont render.
</div>
);
}
Make two class, .green-theme{
color:'green'} and similarly, blue theme.
Mantain a REDUX STATE, CURRENT_THEME. Upon event fire, change the redux state accordingly and everywhere, where you want to use CURRENT_THEME, use it using mapStateToProps.
I would rather try to use almost pure CSS solution:
in App.css
#App.first-theme .theme { color:green; }
#App.second-theme .theme { color:blue; }
in App's render:
<div id="App" className={this.state.currentTheme}>
<AnotherComponent1 />
<AnotherComponent2 />
</div>
All you need to do is to change this.state.currentTheme appropriately. You can even use prop injected from the redux.
Almost all other solutions posted here have the same flaw: you have to adapt all your components to use the theme. Using this solution, you are able to change app's appearance without additional code in your components.
Trust me, injecting the same property from redux store/react context for every component will give you headaches and a lot of unnecessary code.
You should also try to avoid generating additional <style> tags - you will end up having plenty of !important and HTML, logic, and CSS in one file. What a mess! Imagine, what would happen if you would like to use SCSS in the future...
I have a simple React component that accepts a prop that hides/shows a component's children. I hide/show using the style attribute and display: none. If I use display: none !important, the component no longer re-renders when it receives new props.
Within the render method, it looks like this:
var style = {};
if(shouldHide) {
//this works
style = {
display: 'none'
};
//this does not
//style = {
// display: 'none !important'
//};
}
return (
<span style={style} {...this.props} />
);
Here's the full example: https://jsfiddle.net/ccnokes/LnrnrLy2/ (relevant lines start at line 27)
What's going on here? Am I missing something?
!important is currently unsupported - https://github.com/facebook/react/issues/1881
Does not appear they will be adding it any time soon.
They offer this as a workaround:
var sheet = document.createElement('style');
document.body.appendChild(sheet);
sheet.innerHTML = 'html {font-size: 1em !important;}';
But not sure if you want to go down that path or not.
I was able to resolve with a class switch:
//css
.hidden {display: none !important};
//jsx
var hideClass;
if(shouldHide) {
hideClass = "hidden";
}
return (
<span className={hideClass} {...this.props} />
);
Updated
I went ahead and added the workaround above.
And the fiddle here - https://jsfiddle.net/kellyjandrews/oan4grme/
Not exactly the answer you wanted, but it works :)