Tzvetlin Velev
Tzvetlin Velev

Reputation: 2027

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

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>
);}}

Upvotes: 1

Views: 1794

Answers (3)

Mihey Mik
Mihey Mik

Reputation: 1862

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

Upvotes: 0

Brett DeWoody
Brett DeWoody

Reputation: 62851

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.

Upvotes: 1

SALEH
SALEH

Reputation: 1562

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

Upvotes: 1

Related Questions