Is it possible to localize the global styles of a module to only one file?
for instance, I would like to change the width of an item from a react module but only for one file. inline styles aren't possible :/
edit for context: in my particular case ... i'm using 'react-multi-carousel' ... and to go over the breakpoint behavior, I've set .react-multi-carousel-item { width: 310px !important; } . However i'd like this style to be applied only to one component and not my entire project (I'm using the carousel in more than one place). Any way to localize a global style (CSS file)?
You just nest the CSS rule to only apply when inside a specific container:
.my-container .react-multi-carousel-item { width: 310px !important; }
And then in React:
return <>
<MultiCarousel />
<div className="my-container">
<MultiCarousel />
</div>
</>
In that example the first <MultiCarousel /> would not see the extra style, but the second one would.
"is there any way to add css within the TSX file by any chance? If possible, I'd like to not have an external css file."
You could try a scoped style tag
For example:
return <>
<div>
<style scoped>{`
.react-multi-carousel-item {
width: 310px !important;
}
`}</style>
<MultiCarousel />
</div>
</>
Related
I'm porting an app from React to Next and I keep getting an error with my css: "ul" is not pure (pure selectors must contain at least one local class or id).
I'm using css modules and am not sure what the workaround is to keep everything in the css module.
for example:
index.js
<div className={styles.container}>
<ul>
<li>Person One</li>
</ul>
</div>
index.module.css
.container{
background-color: pink;
}
ul{
list-style-type: none; //this throws an error
}
If you don't want to use classes as mentioned #Zeeshan's answer, you cannot use the module-based CSS. You will need to use a global stylesheet to target pure elements as selectors. They cannot be component-scoped.
Further, you can only import a global stylesheet in one place (_app.tsx/_app.jsx/_app.js), or you'll receive an error (explained here).
You may break your styles out across many stylesheets, but they all have to be global, so there's probably little benefit from doing so.
To quote directly from this Next.js GitHub discussion forum:
You are receiving this error because you are using html tags directly instead of classnames or ids in a file extension that is probably [filename].module.(css | scss | sass)
File extensions with *.module.(css | scss | sass) are css modules and they can only target elements using classnames or ids and not using tag names. Although this is possible in other frameworks like create-react-app, it is not possible in next-js.
My suggestion is using these html selector css in a separate file that doesn't contain the '.module' in it.
Example: [filename].(css | scss | sass) --> styles.scss
And instead of importing like this
import styles from './styles.module.scss';
import like this
import './styles.scss';
This is actually extremely simple.
You can add a container class to the top element (just like you did), and then use combinators ( ,+,>, etc.) to target pure elements as you wish.
For example:
index.js:
<div className={styles.container}>
<ul>
<li>Person One</li>
</ul>
</div>
index.module.css:
.container {
background-color: pink;
}
.container ul {
list-style-type: none;
}
Try giving a className or id to ul tag and then write your styles accordingly.
for example:
index.js
<div className={styles.container}>
<ul className={styles.container__list}>
<li>Person One</li>
</ul>
</div>
index.module.css
.container {
background-color: pink;
}
.container__list{
list-style-type: none;
}
I would like to know what can potentially cause styled-components to not inject all the neccessary css into a page's header.
I have declared a super simple button in an existing project like so:
const Button = styled.button`
background-color: ${props => props.disabled ? "red" : "blue"}
`
And used it like so:
render() {
return (
<div>
<input value={this.state.value} onChange={this.changeValue} />
<Button disabled={this.state.value === "123"}>Button</Button>
</div>
);
}
The problem is the button will display as expected on load (eg. red) but it doesn't have the blue style when the state changes.
Looking at the generated html, this is caused by the 'blue' style (.hqrbog) not injected into the header
<style type="text/css" data-styled-components="jiLefI" data-styled-components-is-local="true">
/* sc-component-id: sc-bdVaJa */
.sc-bdVaJa {}
.jiLefI{background-color:red;}
</style>
<div data-reactroot="">
<input value="12" class="drop-val">
<button class="sc-bdVaJa hqrbog">Button</button>
</div>
When I put these code in a new app created with create-react-component, everything works. But they just dont work in this existing project.
I'm wondering what can cause styled-component to not inject css insto the header properly? I'm suspecting its something to do with how the webpack or babel is set up but I don't know where to start.
Try to rename your attribute from disabled to something else.
How can we change the JSX javascript expression delimiters?
For now JSX uses { and } as expression delimiters, but how could we change this delimiters for some of our components? For example, how could we write expressions like ${ 1+1 } or {{ 1+1 }} instead of { 1+ 1}?
The main motivation for this is to use the power of JSX to not just create powerfull HTML-JS-like components but to create CSS-JS-like components too.
For example, I wrote this example in codepen:
function Style(props) {
return <div>
<h1>
{props.children}
</h1>
<style>
{props.children}
h1 {'{'}
color: {props.color};
{'}'}
</style>
</div>;
}
ReactDOM.render(
<Style
color="white"
>
* {'{'}
background-color: red;
{'}'}
</Style>,
document.getElementById('root')
);
This works fine and it's awesome. I think we can create very interesting things with this strategy, for example, do several complex calculations to achive some powerfull style that even css or scss (for example) can't give it to us. We can use the full power of javascript to write our styles if we need this.
But this example will be more readable if JSX just have a little new option to parse expressions using another delimiters like the listed ones above. For example, we could write the same code like this:
function Style(props) {
return <div>
<h1>
${props.children}
</h1>
<style>
${props.children}
h1 {
color: ${props.color};
}
</style>
</div>;
}
ReactDOM.render(
<Style
color="white"
>
* {
background-color: red;
}
</Style>,
document.getElementById('root')
);
So, how can we change the expression delimiters?
Or how can we extend JSX to have this behavior for some special of our components (like Style above)?
Note
This is a simple working example and proposal. It is not to use in all cases and not a proposal to always create html, css and js in the same file. The motivation for this is, when needed, we could bring the javascript power to create our styles, maybe you, as me, could sometimes achieve some result easily with a javascript expression but even in Sass you couldn't. So, I think the approach to bring the javascript power when creating styles will be extremely valid for some cases.
I just worked through the Guide on Vue.js's website, and I have a bad feeling about templates for components. It seems strange to me that they are specified in strings; sure, maybe this works for very short templates, but once you get to multiline templates, you need to start escaping your new lines and it just feels wrong to have html in javascript strings to begin with. Not to mention that syntax highlighting or any other nice IDE features are useless with HTML in JS strings.
Two alternatives that are detailed in the docs are using inline templates, or X-templates, but both of these options are discouraged.
The only other alternative seems to be Single File Components, which seems like a good option, but they are in the Advanced section and in the docs, it is said that for small and medium sized apps, simply using Vue.component should be enough. Furthermore, Single File Components look like they're more difficult to integrate into a project, requiring tapping into the project's build system (the docs talk about Webpack and Browserify).
So I'm confused. Do I just need to accept that my component code is going to look as messy as this example, pulled straight from the docs?
Vue.component('currency-input', {
template: '\
<span>\
$\
<input\
ref="input"\
v-bind:value="value"\
v-on:input="updateValue($event.target.value)"\
>\
</span>\
',
......
Given that you are starting a new project, you can use vue-hackernews-2.0 as boilerplate, where you see lot of components already coded with webpack integration for both dev and prod env. This is also developed by core vue team and recommended in official docs.
You can see there are different files for each component and one component looks like following having clear separation of HTML, JS and CSS part:
<template>
<li v-if="comment" class="comment">
<div class="by">
<router-link :to="'/user/' + comment.by">{{ comment.by }}</router-link>
{{ comment.time | timeAgo }} ago
</div>
<div class="text" v-html="comment.text"></div>
<div class="toggle" :class="{ open }" v-if="comment.kids && comment.kids.length">
<a #click="open = !open">{{
open
? '[-]'
: '[+] ' + pluralize(comment.kids.length) + ' collapsed'
}}</a>
</div>
<ul class="comment-children" v-show="open">
<comment v-for="id in comment.kids" :id="id"></comment>
</ul>
</li>
</template>
<script>
export default {
name: 'comment',
props: ['id'],
data () {
return {
open: true
}
},
computed: {
comment () {
return this.$store.state.items[this.id]
}
},
methods: {
pluralize: n => n + (n === 1 ? ' reply' : ' replies')
}
}
</script>
<style lang="stylus">
.comment-children
.comment-children
margin-left 1.5em
.comment
border-top 1px solid #eee
position relative
.by, .text, .toggle
font-size .9em
margin 1em 0
.by
color #999
a
color #999
text-decoration underline
.text
overflow-wrap break-word
a:hover
color #ff6600
pre
white-space pre-wrap
.toggle
background-color #fffbf2
padding .3em .5em
border-radius 4px
a
color #999
cursor pointer
&.open
padding 0
background-color transparent
margin-bottom -0.5em
</style>
This uses webpack for build and adds working config as well which I myself am using in production without any issue.
You can use <template>...</template> or <script type="text/x-template">...</script>, and specify the selector in template attribute for that.
<template id="myComponent">
<div>
<h1>Hello!</h1>
<p><slot></slot></p>
</div>
</template>
Vue.component('myComponent', {
template: '#myComponent'
})
Simple working example here: http://codepen.io/anon/pen/dNWrZG?editors=1010
Also, the build process of single file components is not that difficult. You can check the webpack-simple template: https://github.com/vuejs-templates/webpack-simple, the vue-loader will do everything for you.
Once you feel comfortable with webpack, you can take a look at the full webpack template: https://github.com/vuejs-templates/webpack
From my experiences, if the template is very short, use inline mode is OK. If not, x-template also allows you to get rid of escaping line breaks. I don't see why you think these approaches are discouraged. Can you provide more information?
However, if you insist to embed long template inline, you can still do that without escaping. The answer is ES6 template literals - string wrapped within ``:
template: `
<span>
$
<input
ref="input"
v-bind:value="value"
v-on:input="updateValue($event.target.value)"
>
</span>
`,
On the other hand, I really think vue-cli is a great tool. Webpack is something worth learning.
This is not really a direct answer (It's editor Specific) but i just thought i should share, but if you're using Visual Studio Code as your editor, Then you can keep your templates as part of your component and still get Syntax highlighting.
Thanks to this awesome extension
angular-2-inline
It was Originally meant for Angular 2, but it works for all ES6 Template strings (Provided the key of Template String is "template").
Single File components are the Recommended way, but they can become a burden when you're not building a Full-fledged SPA and you're just using Vue to enhance some HTML templates Here and there, and you don't want to get Involved with Webpack.
Don't believe it? I'm currently using it.
Thanks to #danidee answer I was able to track an Atom extension to properly do syntax highlighting for "backticked" HTML strings. However as he indicates it will only work when the template is declared inside the very component definition (and I want to separate template in another .js file). So I did this and it's a more ellegant solution, I think:
COMPONENT DEFINITION
/* template definition */
import { csFooterView } from './csfooter-view.js?v6';
/* component definition */
const csfooter = {
name: 'csfooter',
props: ['projectName'],
data: function() {
return {
copyrightCompany: 'CSDev'
}
},
template: csFooterView.template
};
/* exports */
export { csfooter };
TEMPLATE DEFINITION
/**
* VUE Footer Component
* Template
*/
/* template definition */
const csFooterView = {
template: `
<footer class="footer bg-warning p-4 m-auto">
<p>{{ copyrightCompany }} (c) 2020 - {{ projectName }}</p>
</footer>
`
};
export { csFooterView }
ATOM SCREENSHOT WITH HTML SYNTAX HIGHLIGHTING IN THE .JS FILE
Link to Atom extension
How do I center a div element in react with using an external css file. I tried using bootstrap classes and inline styles that other people posted but none of those worked. I was wondering how you guys would implement this without an external css file.
If you don't have to support old browsers, you may look into Flexbox.
https://css-tricks.com/snippets/css/a-guide-to-flexbox/
Try something like this:
<div style={{display: 'flex', justifyContent: 'center'}}>
<div>centered content</div>
</div>
Offsets: The first uses Bootstrap's own offset classes so it requires no change in markup and no extra CSS. The key is to set an offset equal to half of the remaining size of the row. So for example, a column of size 6 would be centered by adding an offset of 3, that's (12-6)/2.
In markup this would look like:
<div class="row">
<div class="col-md-6 col-md-offset-3"></div>
</div>
margin-auto: You can center any column size by using the margin: 0 auto; technique, you just need to take care of the floating that is added by Bootstrap's grid system. I recommend defining a custom CSS class like the following:
.col-centered{
float: none;
margin: 0 auto;
}
Now you can add it to any column size at any screen size and it will work seamlessly with Bootstrap's responsive layout :
<div class="row">
<div class="col-lg-1 col-centered"></div>
</div>
An easy way to do this using react-bootrsrap is
<Grid>
<Row className="text-center"><h1>Our Products</h1></Row>
</Grid>
Use className (instead of class) to take advantage of Bootstrap's built in class of "text-center".
I am using react-bootstrap for this:
export default class CenterView extends React.Component {
render() {
return (
<Grid>
<Row className="show-grid">
<Col xs={1} md={4}></Col>
<Col xs={4} md={4}>{this.props.children}</Col>
<Col xs={1} md={4}></Col>
</Row>
</Grid>
)
}
}
and then in code
<CenterView>
<LoginForm/>
</CenterView>
Have this between the imports and React Class
const styles = {
center: {
marginLeft: "auto",
marginRight: "auto"
}
}
Then to use
<div className={styles.center}>
hi
</div>
I just added:
<Grid container spacing={2} justify="center"></Grid>
For people using React Bootstrap, here I show an example of the classes text-align and justify-content-center. As the names describe, one is for centering text and the other for centering elements.