I was looking at styled-components and I saw this syntax:
const Title = styled.h1`
font-size: 1.5em;
text-align: center;
color: palevioletred;
`;
I can't understand what is going on under the hood and what property is actually applied to the styled object.
Is there anyone that can explain to me how this code even runs?
Read about tagged templates
This is basically a function, but you can run it without ()
const styled = data => {
return data + ' JavaScript';
};
const data = styled `I love`;
console.log(data);
Examples with built-in functions:
console.log('a b c'.split ` `)
console.log(Object.entries `abc`)
console.log([1, 2, 3].concat `abc`)
You create styled h1 element, for example in Header component :
const Title = styled.h1`
font-size: 2rem;
text-align: center;
color: blue;
`;
You use it like a <h1> tag but with custom name:
<Title>My portfolio</Title>
You finally get the static hash class name sc-<hashedStringName> and one is dynamic class:
<h1 class="sc-gsnERi fiwDZi">My portfolio</h1>
So styled-components:
generate static class name
generate dynamic class name
This basically allows you to create Custom Tag in JSX.
You can also pass props to the styling properties in styled-components.
If you have this jsx:
<Title>This is Custom H1</Title>
const Title = styled.h1`
color: red;
`
It will render HTML like this:
<h1 class="someRandomAlphabet">This is Custom H1</h1>
where the class of h1 tag will have these properties:
.someRandomAlphabet{
color: red;
}
Related
Simply put, I want to change the color of the first two texts of each line to white, but it doesn't work anyway. It is as if the span elements generated by js cannot be affected by css.
Please see the picture for the specific code.
Sorry I'm not very good at using Stack Overflow yet, the code has been added.
export default {
mounted(){
console.log("Hello!")
let list = document.querySelectorAll('.shinchou-menu li a')
list.forEach( link => {
let letters = link.textContent.split("");
link.textContent = "";
letters.forEach((words, i) => {
let span = document.createElement("span");
span.textContent = words
if(i < 2){
span.className = "highlight"
}
span.style.transitionDelay = `${i/10}`
link.append(span);
})
})
}
}
<style>
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #fafafa;
}
</style>
<style lang="less" scoped>
.shinchou-menu {
--heightlight-text-color: #00ACF0;
list-style: none;
li {
a {
text-decoration: none;
display: inline-flex;
background: #000;
font-size: 1.6em;
font-weight: 700;
color: var(--heightlight-text-color);
padding: 4px;
margin: 6px 0;
span.highlight {
color: #FFF;
}
}
}
}
</style>
<template>
<div>
<ul class="shinchou-menu">
<li>ニュース</li>
<li>ストーリー</li>
<li>スターフ&キャスト</li>
<li>キャラクター</li>
<li>放送·配信情報</li>
</ul>
</div>
</template>
Don't manipulate DOM directly!
Vue keeps a separate DOM structure (called virtual DOM) where it tracks all elements for reactivity. Whenever something reactive changes, the DOM node in the actual DOM of the page gets re-rendered. Why? Because it's a lot faster than tracking changes in DOM.
What this means is that whenever you change DOM directly, you will lose those mods whenever Vue re-renders.
You are supposed to handle your data in the component and allow Vue to render it using template structural directives (v-if, v-for, etc...).
In your case, that would look something like this (not sure what the word separator is):
Vue2:
new Vue({
el: '#app',
data: () => ({
items: [
'ニュース',
'ストーリー',
'スターフ&キャスト',
'キャラクター',
'放送·配信情報'
]
})
})
.highlighted { color: red }
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.14"></script>
<div id="app">
<ul>
<li v-for="item in items"
:class="{ highlighted: item.split('·').length > 1 }"
v-text="item" />
</ul>
</div>
Vue3:
Vue.createApp({
setup: () => ({
items: [
'ニュース',
'ストーリー',
'スターフ&キャスト',
'キャラクター',
'放送·配信情報'
]
})
}).mount('#app')
.highlighted { color: red }
<script src="https://unpkg.com/vue#3/dist/vue.global.prod.js"></script>
<div id="app">
<ul>
<li v-for="item in items"
:class="{ highlighted: item.split('·').length > 1 }"
v-text="item" />
</ul>
</div>
Note: you can (and maybe should) create a method taking the item as a param and returning the correct classes for the item. This way you don't have to write your js into the template.
<li v-for="item in items" :class="itemClasses(item)">
component:
/* Options API syntax: */
methods: {
itemClasses(item) {
/* return string, array of strings or class object
docs: https://vuejs.org/guide/essentials/class-and-style.html
*/
}
}
/* (alternative) Composition API syntax : */
setup() {
// replace this function with your own logic
const itemClasses = item => item.split('·').length > 1;
return { itemClasses }
}
I need to create a CSS class with media queries based on input image. The react script to create the css should look something like this:
const getBackgroungImageSet = (image) => {
return `.mycontainer {
background-image:url("${image}?mw=500"); // big image
}
#media(max-width: 768px){
.mycontainer {
background-image:url("${image}?mw=250"); // small image
}
}`;
}
Is it possible to add this class to the document in react?
Here's a way to add your styles via a style tag. The actual method is based on something shown in the docs for React Helmet. Which is a good way of getting your style tags to the document head instead of arbitrarily in the middle of the dom.
For the style tag, you need to use type="text/css" and use a string so that there aren't syntax errors due to CSS syntax not being valid in JSX.
function Example() {
return (
<div>
<span>This should be purple</span>
<br/>
<span>This should have a blue border</span>
<style type="text/css">{`
span {
color: purple;
}
span:nth-of-type(2){
color: inherit;
border: 2px solid blue;
}
`}</style>
</div>
);
}
ReactDOM.render(<Example />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"/>
I'm new to Vaadin and trying to create an instance that hides the vaadin-text-field from the component vaadin-date-picker.
I started out by reading the documentation for vaadin-date-picker about the shadow DOM property stated here.
I tried with "Scoping Styles in a Theme Module" but the whole thing including the calendar icon disappeared.
Current code as below,
render() {
return html`
<dom-module id="trim-inputbox" theme-for="vaadin-date-picker">
<template>
<style>
:host(.special_field) [part="text-field"] {
visibility:hidden;
}
</style>
</template>
</dom-module>
<vaadin-date-picker class="special_field"></vaadin-date-picker>
`;
}
Thanks so much again for any kind help.
As you noticed already a calendar icon is part of a text-field itself.
In Styling section there is an example of using <vaadin-date-picker-light>:
<style>
.my-input2 input {
border: none;
font-size: 14px;
background: none;
}
</style>
<vaadin-date-picker-light>
<div class="my-input2">
<iron-icon icon="event"></iron-icon>
CHECK-IN:
<iron-input>
<input size="10">
</iron-input>
</div>
</vaadin-date-picker-light>
Maybe you could use this instead?
Mozilla says Web components consist of three main technologies:
Custom elements
Shadow DOM
HTML templates
Is number 3, "HTML templates", even necessary in light of ECMAscript's Template Literals?
Look at this example I got from James Milner:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Web Component</title>
<script type="text/javascript">
// We define an ES6 class that extends HTMLElement
class CounterElement extends HTMLElement{
constructor() {
super();
// Initialise the counter value
this.counter = 0;
// We attach an open shadow root to the custom element
const shadowRoot= this.attachShadow({mode: 'open'});
// We define some inline styles using a template string
const styles=`
:host {
position: relative;
font-family: sans-serif;
}
#counter-increment, #counter-decrement {
width: 60px;
height: 30px;
margin: 20px;
background: none;
border: 1px solid black;
}
#counter-value {
font-weight: bold;
}
`;
// We provide the shadow root with some HTML
shadowRoot.innerHTML = `
<style>${styles}</style>
<h3>Counter</h3>
<slot name='counter-content'>Button</slot>
<button id='counter-increment'> - </button>
<span id='counter-value'> 0 </span>
<button id='counter-decrement'> + </button>
`;
// We can query the shadow root for internal elements
// in this case the button
this.incrementButton = this.shadowRoot.querySelector('#counter-increment');
this.decrementButton = this.shadowRoot.querySelector('#counter-decrement');
this.counterValue = this.shadowRoot.querySelector('#counter-value');
// We can bind an event which references one of the class methods
this.incrementButton.addEventListener("click", this.decrement.bind(this));
this.decrementButton.addEventListener("click", this.increment.bind(this));
}
increment() {
this.counter++
this.invalidate();
}
decrement() {
this.counter--
this.invalidate();
}
// Call when the counter changes value
invalidate() {
this.counterValue.innerHTML = this.counter;
}
}
// This is where the actual element is defined for use in the DOM
customElements.define('counter-element', CounterElement);
</script>
</head>
<body>
<counter-element></counter-element>
</body>
</html>
Notice how he doesn't use an HTML template, but instead uses an ecmascript template literal to set the innerHTML of the shadowRoot.
After this, he uses querySelector to get internal elements of the shadowRoot and he ultimately adds event listeners to the increment and decrement buttons.
If you were to use a HTML template, instead of an ecmascript template literal, what does this gain you?
Conceptually, I'm struggling to find a situation where I'd prefer an HTML Template Element over an Ecmascript Template Literal.
Please advise.
The template tag is not 'required' for Web Components per se. It probably made more sense when HTML Imports were being pushed, allowing for importing and reusing HTML snippets, but that has since ceased. Here you could have imported a template and reused that.
It's important to note the specifications are designed to be standalone and can be used interdependently of each other also, which makes them versatile. The HTML tag has use cases outside of the realm of Web Components; it's useful because it allows you to define a piece of markup that doesn't render until instantiated via JavaScript later on. Indeed you can use templates without using any of the other specifications (Custom Elements, Shadow DOM etc).
The template tag can certainly be used in conjunction with the other specs. For example, we could have used it in the example shown to arguably make the code less imperative and more markup focused like so:
<template id="counterTemplate">
<style>
:host {
position: relative;
font-family: sans-serif;
}
#counter-increment, #counter-decrement {
width: 60px;
height: 30px;
margin: 20px;
background: none;
border: 1px solid black;
}
#counter-value {
font-weight: bold;
}
</style>
<h3>Counter</h3>
<slot name='counter-content'>Button</slot>
<button id='counter-increment'> - </button>
<span id='counter-value'> 0 </span>
<button id='counter-decrement'> + </button>
</template>
And then use this later in JavaScript like so:
const template = document.querySelector('#counterTemplate');
const counter = document.cloneNode(template);
shadowRoot.appendChild(counter);
The downside here is that it would require that the template existed in the DOM prior to the instantiation as it is relying on the #counterTemplate template being there. In some ways this makes the Custom Element less portable, hence why template literal might be more desirable. I haven't tested the performance of both, but my gut tells me that the template would possibly be more performant.
Disclaimer: I wrote the original blog post
I'm injecting html in my react component using dangerouslySetInnerHTML in a format like this :
<div
className="mt-2 col variant-attr-cell p-0"
dangerouslySetInnerHTML = { {
__html: JSON.parse(attrs[i].snippet).snippet.replace("{text}",
attrs[i].choices[j].visualization_data)
} }
>
</div>
and it works fine but I'm trying to pass style to the injected html at the same time but don't know how!
I'm trying to add different styles to the injected html based on the api I get, something like this:
height: 12px;
width: 12px;
border-radius: 50%;
display: inline-block;
margin: 0 4px;
FYI the injected html is something like this mostly:
<span></span>
and the styles must be added to this and not the container div!
Any solution is appreciated,
thanks.
You can still add the desired style. Just add another props style:
const styleObj = {
color: 'white',
backgroundColor: 'red'
};
<div
className="mt-2 col variant-attr-cell p-0"
dangerouslySetInnerHTML = {
{ __html: JSON.parse(attrs[i].snippet).snippet
.replace("{text}", attrs[i].choices[j].visualization_data)
}
}
style={styleObj}
>
</div>
If you're trying to add style inside the element that resides in the html, then you should have their styles there in the html itself.
I managed to do this by adding a ref to the container and using the useLayoutEffect hook.
const elRef = useRef();
useLayoutEffect(()=>{
if (elRef.current){
elRef.current.firstElementChild.style.height = '12px';
// set other style attributes
...
}
});
return <div
ref={elRef}
dangerouslySetInnerHTML={yourHTML}
/>
This assumes you only want to style the first child of your container, but you could use a similar approach for multiple children.
Since I get the HTML from API, I set the style attribute for the HTML with a static value in the database and replaced the static value from API in my component!
You can easily style element in dangerousHTML like this style='background-color:red' instead style={{backgroundColor:'red'}}