How to style input tag without class with JSS - css

I am using the react-select component on my app. I am also only styling my app with JSS. My issue is that since react-select is an npm package, I don't have the capability to modify class names in the component. So there is an input in there that I need to target with my styles.
<div class="Select-input"><input type="text" name="style-me" /></div>
And my JSS is a little something like this:
jss.setup(preset());
const stylus = {
'Select-input': {
background: 'red'
}
}
const { classes } = jss.createStyleSheet(stylus).attach();
What do I need to do in JSS to style that child input tag?

According to this answer, you can pass in a class name for react-select. The rest of my answer shows how to target child elements.
I checked the github page for JSS here:
https://github.com/cssinjs/jss
They have a live example for nested CSS rules here:
https://github.com/cssinjs/examples/blob/gh-pages/plugins/jss-nested/simple/app.js
In the code to target a nested <button> element, it uses a property named & button. Notice the space between the ampersand and button. So for your specific code, you can target the <input> like this:
jss.setup(preset());
const stylus = {
'Select-input': {
background: 'red',
'& input': {
/* your input styles here */
}
}
}
const { classes } = jss.createStyleSheet(stylus).attach();

Assuming you're referring to this package:
https://github.com/JedWatson/react-select
You can in fact pass in className as a prop

You have always at least 2 ways:
Pass the generated class name
Use JSS as you should by default, avoid unscoped class names. Use generated class name and pass it to the component you want to use
const {classes} = jss.createStyleSheet({
input: {background: 'red'}
}).attach()
<Input className={classes.input} />
Use scoped global selector
If its impossible to pass a class name, you can still have a locally scoped global selector
const {classes} = jss.createStyleSheet({
container: {
'#global': {
input: {background: 'red'}
}
}
}).attach()
<div className={classes.container}>
<Input />
</div>

Related

How to make autosuggest field look like bootstrap input?

How can I make the <vue-autosuggest> input look like the input from BootstrapVue (<b-input>)?
To apply the form-control class to vue-autosuggest's inner <input>, as required for the Bootstrap <input> styles, you could use the inputProps prop (automatically applied to the <input>):
<template>
<vue-autosuggest :input-props="inputProps">
...
</vue-autosuggest>
</template>
<script>
export default {
data() {
return {
inputProps: {
class: 'form-control',
}
}
}
}
</script>
Interestingly, that class used to be added by default in vue-autosuggest 1.x, but was removed in 2.x.
demo
You need to modify the the <input> tag of the vue-autosuggest component to include the class form-control from Vue-Bootstrap.
You will not be able to add this class directly to the component as the component wraps the input within a div block. Bootstrap CSS requires the the element to be of type input to properly match the CSS selectors.
If we look here https://github.com/darrenjennings/vue-autosuggest/blob/master/src/Autosuggest.vue at the component itself we see
<input
:type="internal_inputProps.type"
:value="internalValue"
:autocomplete="internal_inputProps.autocomplete"
:class="[isOpen ? `${componentAttrPrefix}__input--open` : '', internal_inputProps['class']]"
v-bind="internal_inputProps"
aria-autocomplete="list"
:aria-activedescendant="isOpen && currentIndex !== null ? `${componentAttrPrefix}__results-item--${currentIndex}` : ''"
:aria-controls="`${componentAttrIdAutosuggest}-${componentAttrPrefix}__results`"
#input="inputHandler"
#keydown="handleKeyStroke"
v-on="listeners"
>
This must be modified in your local version to include the bootstrap class.

Add a class to the parent .wp-block element in gutenberg editor

When Gutenberg creates a class, it seems to be of the format
div.wp-block
div.editor-block-list__insertion-point
div.editor-block-list__block-edit
div.editor-block-contextual-toolbar
div
<your actual block html goes here>
I'd like to be able to add a class to that top div.wp-block element so I can properly style my block in the editor. The class is dynamically generated based on an attribute so I can't just use the block name class. Is there a clean way of doing this? I can hack it using javascript DOM, but it gets overwritten quickly enough.
https://wordpress.org/gutenberg/handbook/designers-developers/developers/filters/block-filters/#editor-blocklistblock
const { createHigherOrderComponent } = wp.compose
const withCustomClassName = createHigherOrderComponent((BlockListBlock) => {
return props => {
return <BlockListBlock { ...props } className={ 'my-custom-class' } />
}
}, 'withCustomClassName')
wp.hooks.addFilter('editor.BlockListBlock', 'my-plugin/with-custom-class-name', withCustomClassName)
You can add class in your block edit view by using className that is present in this.props, className will print class in following format wp-blocks-[block_name]
edit( { className } ) { // using destructing from JavaScript ES-6
return <div className={ className }></div>
}
Suggestion
Always try to look for manipulating DOM via React instead of manipulating DOM directly because React manages it's own state and issues can occur by manipulating DOM directly.

How to dynamically change css selector property value in react js code?

I need to dynamically change the color in the react component for specific selector.
In scss (use sass) i have the following rule:
foo.bar.var * {
color: blue;
}
I want to change it in react code, to be yellow, red or something else.
I cant use style property for element, cause i need the selector to
apply for all subchilds !=)
Is there any native ways? Or should i use Radium? Or is there any similar libs for this? Maybe css-next some hove can help with this?
I have color picker, i cant write class styles for every color =(
For some answerers NOTE:
So i have selector in some scss file, that imported in some root js file with .class * {color: $somecolor} and i need change the $somecolor in that selector, during picking colors in color picker
Maybe i can somehow set selector for all nested inside style property? or there is the way how to recursively apply css style for every nested items from the style prop?
What about
class MyComponent extends React.Component {
render() {
const yellow = true // Your condition
return(
<div className={`foo bar var ${yellow && 'yellow'}`}
My item
</div>
)
}
}
.foo.bar.var {
& * {
color: blue;
}
&.yellow * {
color: yellow;
}
}
You could define a custom CSS property (CSS variables) using the style attribute of the element and assign the value to a prop, state etc.
<div className='foo bar var' style={{ "--my-color": props.color }}></div>
The custom property would work for any selector that apply to that component or children. So you could use it like that:
foo.bar.var * {
color: var(--my-color);
}
See a snippet with similar code here
this may sound stupid . but does this work ?
import myCss from './mydesign.css';
myCss.foo.bar.var = "your color"

Responsive Props in Vue Component

I have a prop called src in a Vue Component that binds to a :style like this:
<template>
<section :class="color" class="hero" :style="{ backgroundImage: src && 'url(' + src + ')' }">
<slot></slot>
</section>
</template>
<script>
export default {
props: ['src', 'color']
}
</script>
What I would like to do is to create a list of responsive props that get used depending on the device or screen size of the site visitor.
For instance, I imagine a list of props like src-sm, src-md, src-lg, etc. The user would enter different image urls for different device sizes and the style attr would use the appropriate url depending on the screen/size.
Is this possible in VueJS. If so, any idea how?
Thanks.
Unfortuently what you are trying to do is not trivial. This is because inline style tags can not accept media queries.
The spec declares:
The value of the style attribute must match the syntax of the contents of a CSS declaration block
Solution 1:
This solution is the simplest, perhaps not entirely what you are looking for.
It works by including img elements, and showing an hiding them via CSS.
<template>
<div>
<img class="image--sm" :src="src.sm" />
<img class="image--md" :src="src.md" />
<img class="image--lg" :src="src.lg" />
</div>
</template>
<script>
export default {
props: {
src: Object
}
}
</script>
<style>
.image--md,
.image--lg {
display: none;
}
#media (min-width: 400px) {
.image--sm {
display: none;
}
.image--md {
display: block;
}
}
#media (min-width: 600px) {
.image--md {
display: none;
}
.image--lg {
display: block;
}
}
</style>
Example: https://jsfiddle.net/h3c5og08/1/
Solution 2:
Image tags may not be the desired effect you are trying to achieve. This solution creates a style tag in the head and injecting the css content to change the background images.
You can not have style tags in Vue template. It will throw an error like:
Templates should only be responsible for mapping the state to the UI. Avoid placing tags with side-effects in your templates, such as , as they will not be parsed.
As the error describes vue is designed the map state the UI. Using style tags in the template is prohibited because you can cause leaks to the outer world.
Although you can not declaratively styles in a template, we can use a bit of JS in the mounted hook of the component to add targetted and dynamic styles.
First we will need to constrain dynamic styles to this element. We can use the internal id of the created component this._uid, attaching to scope the css. (Note this is internal API so can be subject to change)
<template>
<div class="image" :data-style-scope="_uid">
</div>
</template>
The next part is to generate the style in a computed property, to later inject into a style block. You can expand on this computed property, to conditionaly assign properties ect. Note: keep the properties to the dynamic values only.
css () {
const selector = `.image[data-style-scope="${this._uid}"]`
const img = val => `${selector} { background-image: url("${val}"); }`
const sm = img(this.sm)
const md = img(this.md)
const lg = img(this.lg)
return `
${sm}
#media (min-width: 200px) { ${md} }
#media (min-width: 300px) { ${lg} }
`
}
This generated string from the css computed property is what we will now use when creating the style tag at mount. At mount we create a style node and append to the head. Assigning the nodes to the vm for references.
Using the references in the vm we can watch changes to the computed updating the style node.
Remember to clean up before destorying the component, removing the style node.
{
data () {
return {
// Reference data properties
style: null,
styleRef: null
}
},
mounted () {
// Create style node
let style = document.createElement('style')
style.type = "text/css"
style.appendChild(document.createTextNode(''))
// Assign references on vm
this.styleRef = style
this.style = style.childNodes[0]
// Assign css the the style node
this.style.textContent = this.css
// Append to the head
document.head.appendChild(style)
},
beforeDestroy () {
// Remove the style node from the head
this.style.parentElement.removeChild(this.style)
},
computed: {
css () {
// ...
}
},
watch: {
css (value) {
// On css value change update style content
this.style.textContent = this.css
}
}
}
Working Example: https://jsfiddle.net/bLkc51Lz/4/
You could also try the module described here: https://alligator.io/vuejs/vue-responsive-components/ which is called vue-responsive-components
It lets the component change its CSS depending on its own width (not on the entire browser's width)

Change style of pseudo elements in angular2

Is it possible to change style of pseudo elements using [style] or [ngStyle] in angular2?
in order to get a blur effect on a div acts like an overlay, and I should set up background-image on pseudo element.
I tried something like
<div class="blur" [style.before.backgroundImage]="'url('+ featuredImage[i] + ' )'">
it didn't work. I also tried this
<div class="blur" [ngStyle]="'{:before{ background-image:url('+ featuredImage[i] + ' )}}'">
You can achieve what you need with CSS variables.
In your style sheet you can set the background image like this:
.featured-image:after { content: '';
background-image: var(--featured-image);
}
After that you can programmatically set this variable on the same element or higher up in the DOM tree:
<div class="featured-image" [ngStyle]="{'--featured-image': featuredImage}">
More about CSS variables here: https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables Note that the browser support is not complete yet.
Also note that you will need to sanitize the url/style using sanitizer.bypassSecurityTrustResourceUrl(path) or sanitizer.bypassSecurityTrustStyle('--featured-image:url(' + path + ')')):
No it's not possible. It is actually not an Angular issue: pseudo elements are not part of DOM tree, and because of that do not expose any DOM API that can be used to interact with them.
Usual approach if you want to deal with pseudo elements programmatically is indirect: you add/remove/change class and in CSS make this class affect corresponding pseudo-element. So in your case you could have one more class that changes necessary style:
.blur:before {/* some styles */}
.blur.background:before {/* set background */}
Now all you need to do is to toggle .background class on the element when you need before pseudo-element to get a background. You can use NgClass, for example.
if you want to add other properties I did it like this:
<div class="progress" [style]= "'--porcentaje-width:' + widthh " ></div>
and the css:
.progress::after {
content: '';
width: var(--porcentaje-width);
}
this worked for me :)
With current versions of Angular 2+ you can use CSS Variables to achieve this as well as sanitizing your input.
In your style sheet define the rule using CSS Variables. A fallback can also be defined as CSS Variables aren't supported by IE.
https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties
.featured-image:after {
content: '';
// Fallback for IE
background-image: url('fallback-img.png');
background-image: var(--featured-image);
}
Rather than bypassing security trust style, you can also sanitize your input with a reusable pipe:
https://angular.io/api/platform-browser/DomSanitizer#sanitize
import {Pipe, PipeTransform, SecurityContext} from '#angular/core';
import {DomSanitizer, SafeStyle} from '#angular/platform-browser';
#Pipe({
name: 'safeStyle',
})
export class SafeStylePipe implements PipeTransform {
constructor(protected sanitizer: DomSanitizer) {}
transform(value: string): SafeStyle {
if (!value) return '';
return this.sanitizer.sanitize(SecurityContext.STYLE, value);
}
}
In your template:
<div class="featured-image" [style.--featured-image]="featuredImage[i] | safeStyle"></div>

Resources