Target native dom element <input>...</input> with styled-components - css

I am having trouble getting my styled component to make a change to an <input /> wrapped in a React component. In Dev Tools I can see the style I am trying to override here:
.ui.input input {...}
I think the wrapping component needs to pass className to input i.e
<input className = {this.props.className} ..> ... </input>
but I cannot get the style to override with or without that. I will provide some snippets below.
//styled component
const StyledSearch = styled(Searchbar)`
&.ui.input input{
border: 0px !important;
}
`;
class SearchBar extends Component {
...
render() {
const style = {
display: this.state.showResults ? 'block' : 'none',
maxHeight: 500,
overflowY: 'scroll',
};
return (
<div className="ui search fluid" ref="container">
<div
className={`ui icon fluid input ${this.props.loading ? 'loading' : ''}`}>
<input type="text"
placeholder={this.props.placeholder}
onFocus={this.focus}
className = {this.props.className}
value={this.props.value}
onChange={this.props.onChange}/>
<i className="search icon"></i>
</div>
<div
className="results"
style={style}>
{
this.props.results.map((result, index) => (
<a
className="result"
key={index}
onClick={this.select.bind(this, result)}>
<div className="content">
{
result.get('image') ?
(
<div className="image">
<img src={result.get('image')} style={{ maxWidth: 50 }}/>
</div>
) : null
}
<div className="title">
{result.get('title')}
</div>
<div className="description">
{result.get('description')}
</div>
</div>
</a>
)
)
}
</div>
</div>
);}}

Basically, styled-components creates a new unique class name (in other words, a new namespace) for any DOM or React Components for which the styled function is called.
That means, when you use styled(SearchBar), styled-components wraps SearchBar component and attaches a unique class name to its root DOM. Then it passes that unique class name to the descendent DOMs and components (in your cases, nested div, input, a).
For this method to work, your root DOM must have a className that can be configured from outside. That's why, styled-components expects that, root DOM has the definition ${this.props.className} as the value of its className props. If your component lacks this, styled-components will not be able to create a new namespace which it can use to apply styling specific to it.
So, for your technique to work, you must assign ${this.props.className} as one of the values of className prop defined at the root div of SearchBar.
Working Demo
If you don't have access to SearchBar, you can wrap it with another component. Overhead of this process is that, you have to use an extra DOM level
Working Demo

From what I can tell, you need to apply the styles generated with styled-components to the wrapper element. This is due to the specificity of the .ui.input input external style. Meaning we can't simply target the input element with a new style because the .ui.input input selector is more specific and takes precedence. Here's a simple CSS example showing how the specificity of the .ui.input input selector takes precedence over the input styling:
.ui.input input {
border:2px solid red !important;
}
input {
border: 0px !important;
}
<div class="ui input">
<input />
</div>
This same issue is at play in your case. In the example below I've created a new Wrapper component, which has a style of:
&.ui.input input {
border: 0px !important;
font-size: 24px;
}
defined on it. This targets the inner input element, with more specificity, to override the external styles.
import React from 'react';
import ReactDOM from 'react-dom';
import styled from 'styled-components';
class InputWrapper extends React.Component {
render() {
const Wrapper = styled.div`
&.ui.input input {
border: 0px !important;
font-size: 24px;
}
`;
return(
<Wrapper className="ui input">
<input type="text" placeholder="Input" />
</Wrapper>
)
}
}
ReactDOM.render(
<InputWrapper />,
document.getElementById("app")
);
Here's a WebpackBin example.

Currently at version 4 you can do it as simple as
const Input = styled.input`
border:2px solid red !important;
`;
it will rendered as native input with SC className

Related

How to apply style using jsx-styled to an Image component

Next.js introduced the Image component. I would like to use it and I am currently struggling to find the way to apply style to it using styled-jsx.
Here is my attempt:
export default function MyComponent({description}) {
return (
<div>
<Image src={concept.icon.url} className="icon" width={40} height={40}></Image>
<div>{description}</div>
<style jsx>{`
.icon:hover {
cursor: pointer;
}
`}</style>
</div>
);
}
The classname is properly transmitted to the underlying dom element, but the style is not applied.
Is there some kind of incompatibility between next.js Image component and styled-jsx?
You need :global() selector.
From styled-jsx documentation (One-off global selectors): "This is very useful in order to, for example, generate a global class that you can pass to 3rd-party components."
CODE:
export default function MyComponent({description}) {
return (
<div>
<Image src={concept.icon.url} className="icon" width={40} height={40}></Image>
<div>{description}</div>
<style jsx>{`
div :global(.icon:hover) {
cursor: pointer;
}
`}</style>
</div>
);
}

Why does styling a Bootstrap modal with dialogClassName set and using Styled JSX require the global tag?

I am using Next.js (React) with Bootstrap and styled JSX. I am running into an issue where a custom class in Bootstrap for a modal is only styled with css if the css if global. I declare the custom class using the dialogClassName property on the Modal. This is my function component (I am using Typescript):
const Form: React.FunctionComponent<props> = (props: props) => {
const [FormVisibility, FormDispatch] = useContext(FormContext);
return (
<Modal
show={props.isVisible}
onHide={() => {FormDispatch({ type: ActionTypes.CloseForm }) }}
backdrop="static"
dialogClassName="custom-modal"
>
<Modal.Header closeButton >
<Modal.Title>Modal heading</Modal.Title>
</Modal.Header>
<Modal.Body>Woohoo, you're reading this text in a modal!</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={() => {FormDispatch({ type: ActionTypes.CloseForm }) }}>
Close
</Button>
</Modal.Footer>
<style jsx global>{`
.custom-modal {
color: blue;
height: 75vh;
width: 75vw;
max-width: none !important;
}
`}
</style>
</Modal>
);
}
This works just fine. But if I were to change <style jsx global> to <style jsx> then the styling isn't applied. Am I doing something wrong here or is there a better way to do this? It seems weird to me that global is needed even though the component has the class declared locally.
Thanks!
My experience working with Modals is that the modal element is actually extracted out of the DOM tree where your component lives and placed at the top most level right under the body tag.
<body>
// Component where the Modal is declared
<Form />
<div>
// Modal appears here
// Styles are not applied because Modal is not nested within Form component
</div>
</body>
It is possible that your local style is not applied because of this reason.

internal CSS styling in React at the top of code

I'm trying to style a component in my React application, but I do not want to create an external stylesheet because it's a small project. How can I style this image component without using an external stylesheet?
return (
<div>
<Image>
<div>
<img src='./resources/image.png alt='image'>
</div>
</Image>
</div>
);
I've found resources online for using inline styling on a specific element, but I want to make my code clean by putting it at the top of the component like using a style tag at the top of an HTML file. I haven't been able to find anything that resembles this in React.
For inline styles you can define a style object, either at the top of the file, or in your render method, and then refer to it:
var myStyle = { margin: 10 }
return (
<div>
<Image>
<div>
<img style={myStyle} src='./resources/image.png alt='image'>
</div>
</Image>
</div>
)
More info in the docs: https://reactjs.org/docs/dom-elements.html#style
Internal CSS styling in JSX is very similar to how it's done in HTML. The only difference is that you need to declare the style names as variables because they are treated like JS objects. With this in mind, you also need to end each property with a comma instead of a semicolon, and the last property should have no punctuation at the end. Using this approach, you should also use style={} instead of className={}. You can read more about JSX styling here.
const myStyle = {
width: '300px',
height: '300px',
border: '2px solid black'
}
const Image = () => {
return (
<div>
<img style={myStyle} src='./resources/image.png alt='image'>
</div>
);
}
You can do something like this:
const Image = styled.div`
background: #1d9ac2;
img {
border: 1px solid red;
}
`;
There are several solutions for this, and a big debate about which one is "the best".
I don't know which one is the best, but I can tell you which one I use:
Styled components (https://www.styled-components.com/)
With this, you would define an object like this
let styled = require('styled-components');
// Or for fancy people
import styled from 'styled-components';
const Image = styled.div`
background-color: red;
/* You can even put classes or selectors in here that will match the sub-components */
.some_class_used_inside { color: black; }
img { width: 100px }
`
and use it like this
return (
<div>
<Image> {/* This will be the `<div>` with `background-color: red` */}
<div className="some_class_used_inside"> {/* This will now have `color: black` applied */
<img src='./resources/image.png alt='image'> {/* This will have `width: 100px` applied to it */}
</div>
</Image>
</div>
);
Ofcourse, there are many other libraries to do it, and everyone will have to find their own favorite I guess :)

Selector in css file for reactstrap component

What do I want to achieve
So there is a gap between my jumbotron and my footer. I want to remove that gap. I did it already successfully by setting the margin-bottom to 0px; But at that moment, I had to pass an ID to the Jumbotron element. Now I want to achieve that same effect without passing an ID, but with classes.
I don't want to use inline styles. I want it in a separate css file.
In an old library (react-bootstrap not reactstrap) I could select for example all components from a certain type, like I did in the css provided below.
So the mistake is probably the selector in the css file. I couldn't find anything online which specifically shows it in a seperate "css file" way. Only with inline styling.
MainContent.js
import React from 'react';
import './MainContent.css';
import { Jumbotron, Button, Form, FormGroup, Label, Input, Container } from 'reactstrap';
const MainContent = () => {
return (
<Container>
<Jumbotron>
<Form>
<FormGroup>
<Label for="exampleEmail">Email</Label>
<Input type="email" name="email" id="exampleEmail" placeholder="with a placeholder" />
</FormGroup>
<FormGroup>
<Label for="examplePassword">Password</Label>
<Input type="text" name="password" id="examplePassword" placeholder="password placeholder" />
</FormGroup>
<Button>Submit</Button>
</Form>
</Jumbotron>
</Container>
);
}
export default MainContent;
MainContent.css
.Container {
margin-bottom: 0px;
}
.Jumbotron {
margin-bottom: 0px;
}
If you don't want to do it with IDs or with inline-styling, there is a way I would call a hack.
In MainContent.js add className attribute to the component as follows:
<Jumbotron className="jumbotron">
And in MainContent.css add !important in the statement you want to override other stylings:
.Container {
margin-bottom: 0px;
}
.Jumbotron {
margin-bottom: 0px !important;
}
Unless you override like this, margin-bottom: 2rem from node_modules/bootstrap/dist/css/bootstrap.css is used.

How to style one react component inside another?

I'm new to css and I can't figure out how to position one component inside another in React. I can show them separately, but when I put one inside another. I don't see the one inside. I think the problem is in the css file
#homePage{
section{
h1{
text-align: left; //this is shown
}
//here I want to add the other React component but I don't know how
}
}
And the render method:
<div id="homePage">
<Component1>
<section>
<h1>Hi</h1>
<Component2>
</Component2>
</section>
</Component1>
</div>
Thanks.
From what i understand , you could have the className attribute defined inside your Component2's HTML tags.
class Component2 extends Component{
render(){
return(
<section className="component2styles">
This is Component2
</section >
);
} }
Now , you can change ur style sheet as
#homePage{
section{
h1{
text-align: left; //this is shown
}
//components2 style will be nested here
section.component2styles{
border:1px solid blue;
}
}
}
Or as an alternative you can try inline-styles , seems to be gaining a lot of traction in React development.
render(){
var styleobj={color:'red'};
return( <section style={styleobj} > This is Component 2 </section> )
}
Did you add some class/id to your Component2 like <Component2 className="my-specific-class" /> to style it?
(btw, I hope your css is less/sass one to allow nested styles like you did)
EDIT
By adding className attr. to your Component2, I mean adding it in Component2 render method like
render: function() {
return (
<div id="your-id" className="your-class">
some html here
</div>
);
}

Resources