Scoping v5 MUI Styles - css

We have a legacy application that we're slowly migrating to React and MUI. In order to prevent overlap in styling between the different parts of our application that haven't been converted and vice versa, we've scoped styles by using an id selector in combination with a descendant selector. For example, our styles look like this:
Example output for our styles:
This allows us to prevent our legacy styles from affecting our newer styles and our newer styles from affecting our older styles. Before MUI v5 was released we were able to do this using a custom JSS plugin and prepend the id selector. However, we're trying to upgrade MUI and phase out JSS completely. Is there a way to do this with v5 using the supported styling engines?
Thanks for any help in advance.

I also have the same usecase and stylis-plugin-extra-scope dosen't help us because it only supports Stylis 3, but MUI v5 is using Stylis 4.
So, I added the plugin of Stylis 4 like bellow.
It works for me, but I made this only for me and I am not sure if it works for you.
import createCache from '#emotion/cache'
import { CacheProvider } from '#emotion/react'
const continerId = 'myContainerId'
const container = document.getElementById('div')
const root = createRoot(container)
const cache = createCache({
key: 'ScopedSelector',
stylisPlugins: [
(element) => {
// if it is a class selector, add the selector like '#myContainerId '
if (element.type === 'rule' && Array.isArray(element.props)) {
element.props = element.props.map((prop) =>
prop.startsWith('.') ? `#${containerId} ${prop}` : prop
)
}
},
],
})
root.render(
<CacheProvider value={cache}>
{/* Any Your Components */}
</CacheProvider>
)

A custom Stylis plugin? It can be added in https://emotion.sh/docs/#emotion/cache#createcache and https://github.com/Andarist/stylis-plugin-extra-scope could give an idea on how to use it.

Related

Material-UI - why different css is shown on prod environment then development env

I use material UI (verison: ^4.12.3) Select, with custom input.
For some reason the prod env Select input has a black background and :before element with white background.
I don't know from where it comes from.
this is image of the prod:
this is image of the dev Select:
when comparing the 2 css & html of the envs Select element, it's is shown that there is a ::before element added in prod that is not presented in dev
also, the background color is different. in prod there is another class added to the InputBase element, which doesn't exist in dev. this class adds a background-color black:
Edit 1
it seems like MUI inject <style>. in the prod html i see the background-color: black and the ::before. ill try adding the index solution, but my problem is not precedence (the style that i do use override the injected style). also, it wont help the ::before element. how to disable the injected styles ? or work around it ?
the injected bad css:
Please refer to this question. As answered by user Mordechai.
It seems like webpack could mess with MUI's rules on JSS precedence... This could be solved by adding an index of one to MUI's methods.
//Hook
const useStyles = makeStyles({
// your styles here
}, {index: 1})
// HOC
MyComponent = withStyles({
// your styles here
}, {index: 1})(MyComponent)
adding <StylesProvider /> wrapper to the app fixed it. we use micro-frontend infrastructure. and one of the frontends app also had makeStyles. this is causing classNames conflicts in MUI.
in the root component <App/>:
import {
StylesProvider,
createGenerateClassName
} from '#material-ui/core/styles';
const generateClassName = createGenerateClassName({
seed: 'app1'
});
const App = () => {
return (
<StylesProvider generateClassName={generateClassName}>
<OtherAppComponents />
</StylesProvider>
)
}
if you have more then 2 add a provider and a generator to each, with different seed

Using Tailwind Forms Plugin with React Select

I am trying to integrate Select from react-forms with tailwind css and the tailwind forms plugin (#tailwindcss/forms).
With only tailwind and react-select, the form renders correctly. However, with the plugin, an outline appears. I would like for tailwindcss forms not to interfere with react-select styling. Is there an effective solution to allow react-select styles to override tailwind plugins?
Additionally, please let me know if there are any effective solutions for styling react-select forms using tailwind without resorting to other libraries, like emotion or styled-components.
You can set the box shadow to none for the input when focused
<Select
....
styles={{
input: (base) => ({
...base,
'input:focus': {
boxShadow: 'none',
},
}),
}}
/>
Additionally, please let me know if there are any effective solutions
for styling react-select forms using tailwind without resorting to
other libraries, like emotion or styled-components.
The answer to this is to use this library
https://github.com/ben-rogerson/twin.macro
Example, you can do something like this:
import tw from 'twin.macro';
import ReactSelect, { Props } from 'react-select';
const Styled = {
Select: tw(ReactSelect)`rounded-lg text-center border-2`
};
const Select: React.FC<Partial<Props>> = (props) => {
return (
<Styled.Select {...props} />
);
};
You could use the class strategy for the plugin, it will disable the extra styling, but you will need to implement the form-* class to every other input.
Here is the documentation for it.

How to use react-jss within react class Components?

In react-jss documentation, the authors have written:
'HOC based API is deprecated as of v10 and will be removed in v11.'
This means, as far as I understand, that such HOC functionality as injectSheet and withStyles will no longer be available in V11.
The new react-based stylesheet generating functions seem to be all based on react hooks. The function createUseStyles seemed very promising to myself and my team, until upon looking further into the source code we realised that it was only available within functional components, as it makes use of hooks.
The Problem
As a team we still make heavy use of React Class components and have no plans to move completely to hooks, not because hooks aren't useful, but because sometimes functional components aren't the best or most organised solution to writing a component.
Perhaps I'm missing something-- but it seems like there is now no solution left for React Class based components, other than writing our own manual implementation from core jss.
What solutions are there for a developer to make use of react-jss in a way similar to that achieved by createUseStyles, keeping up with the latest version of react-jss, being able to pass dynamic props, and etc. without writing a manual implementation?
While not specific to JSS, keep in mind that you can always use a tiny wrapper to convert any Hook to render prop or a HOC.
Converting Hook to a render prop is described here: https://reacttraining.com/blog/using-hooks-in-classes/
You can use a similar approach to convert any Hook to a HOC.
import { Classes } from 'jss';
import { createUseStyles } from 'react-jss';
First, lets create a more type safe function for creating styles.
export function createStyles(classes: { [name: string]: Partial<CSSStyleDeclaration> }) {
return createUseStyles(classes as any);
}
Secondly, we'll create a simple wrapper to allow hooks for our components.
function Styles<T extends string | number | symbol>(props: { styles: () => Classes<T>, children: (classes: Classes<T>) => ReactElement }) {
const classes = props.styles();
return props.children(classes);
}
Example
const styles = createStyles({
title: {
fontSize: '25px',
textTransform: 'uppercase'
},
message: {
color: 'red'
}
});
export const App = () => (
<Styles styles={styles}>
{classes => (
<Fragment>
<h1 className={classes.title}>Title</h1>
<p className={classes.message}>message</p>
</Fragment>
)}
</Styles>
);
Output

How to prefix Bootstrap 4 classes to avoid css classes conflict

I am working on building small applications that will live in a website. The website that will host these applications may or may not be using a css framework. I Want to prefix all Bootstrap classes with my own unique prefix.
To avoid "ANY INSTANCE or CHANCE" of conflict I want to prefix all Bootstrap CSS classes with - let's say - "year19-" prefix. So, for example, all the col- classes would now be year19-col- and all the .btn classes would now become .year19-btn, .year19-btn-primary, etc...
I know if I use the sass theme, new classes, then we would get around some of that as we can create our own prefixes using the theming approach, but JS would still remain a source of conflict if two versions of the same framework live on the same page. There was a Github project for Bootstrap 3 with the namespacing feature where you could just add your prefix in the namespace variable then compile the entire code to a CSS and JS package. Bootstrap 4 doesn't seem to have that package yet.
Also, I don't want to wrap the project with a css class. That approach is fine for some things, but not the right approach. I wouldn't even call that namespace. That is just wrapping the classes.
year19-btn-primary {
then this would be whatever the code that already existed there before, not touched.}
I managed to get classes prefixed for Bootstrap 5.1.3. You'll need to make the following changes before compiling Bootstrap yourself. My full implementation is available here: https://github.com/Robpol86/sphinx-carousel/tree/85422a6d955024f5a39049c7c3a0271e1ee43ae4/bootstrap
package.json
"dependencies": {
"bootstrap": "5.1.3",
"postcss-prefix-selector": "1.15.0"
},
Here you'll want to add postcss-prefix-selector to make use of it in postcss.
postcss.config.js
'use strict'
const prefixer = require('postcss-prefix-selector')
const autoprefixer = require('autoprefixer')
const rtlcss = require('rtlcss')
module.exports = ctx => {
return {
map: ctx.file.dirname.includes('examples') ?
false :
{
inline: false,
annotation: true,
sourcesContent: true
},
plugins: [
prefixer({
prefix: 'scbs-', // ***REPLACE scbs- WITH YOUR PREFIX***
transform: function (prefix, selector) {
let newSelector = ''
for (let part of selector.split(/(?=[.])/g)) {
if (part.startsWith('.')) part = '.' + prefix + part.substring(1)
newSelector += part
}
return newSelector
},
}),
autoprefixer({
cascade: false
}),
ctx.env === 'RTL' ? rtlcss() : false,
]
}
}
This is where the CSS will be prefixed. I'm using postcss instead of just wrapping bootstrap.scss with a class/id selector so I can use the Bootstrap 5 carousel component on Bootstrap 4 webpages (which is my use case). This will replace https://github.com/twbs/bootstrap/blob/v5.1.3/build/postcss.config.js
rollup.config.js
// ...
const plugins = [
replace({ // ***COPY/PASTE FOR OTHER BOOTSTRAP COMPONENTS***
include: ['js/src/carousel.js'], // ***YOU MAY NEED TO REPLACE THIS PATH***
preventAssignment: true,
values: {
'CLASS_NAME_CAROUSEL': '"scbs-carousel"', // ***USE YOUR PREFIXES HERE***
'CLASS_NAME_ACTIVE': '"scbs-active"',
'CLASS_NAME_SLIDE': '"scbs-slide"',
'CLASS_NAME_END': '"scbs-carousel-item-end"',
'CLASS_NAME_START': '"scbs-carousel-item-start"',
'CLASS_NAME_NEXT': '"scbs-carousel-item-next"',
'CLASS_NAME_PREV': '"scbs-carousel-item-prev"',
'CLASS_NAME_POINTER_EVENT': '"scbs-pointer-event"',
'SELECTOR_ACTIVE': '".scbs-active"',
'SELECTOR_ACTIVE_ITEM': '".scbs-active.scbs-carousel-item"',
'SELECTOR_ITEM': '".scbs-carousel-item"',
'SELECTOR_ITEM_IMG': '".scbs-carousel-item img"',
'SELECTOR_NEXT_PREV': '".scbs-carousel-item-next, .scbs-carousel-item-prev"',
'SELECTOR_INDICATORS': '".scbs-carousel-indicators"',
}
}),
babel({
// Only transpile our source code
// ...
Lastly rollup replace plugin is used to add the prefixes in the compiled javascript file. I wasn't able to find a way to just prefix the consts so I had to resort to having the entire const replaced and hard-coded with the full class names. This means you'll need to do this for every Bootstrap component that you're including in your final build (for me I just need the carousel so it's not a big deal).

How to use react-jsonschema-form with material-ui?

I am doing a form using react-jsonschema-form, but i really want to customize my application (including the form) with the Material-UI.
I am having trouble to use both together because react-jsonchema-form uses a uiSchema for styling and the Material-UI is set on a prop like this :
SimpleModal.propTypes = {
classes: PropTypes.object.isRequired,
};
<FormControl className={classes.formControl}>
How can i use the Material-UI inside the schema forms?
Now you can start use it with standard react-jsonschema-form library! I searched for a long time and found that now it can already be done.
This PR explain using HOC: https://github.com/mozilla-services/react-jsonschema-form/issues/1222
GitHub: https://github.com/cybertec-postgresql/rjsf-material-ui
Playground with material-ui components: https://cybertec-postgresql.github.io/rjsf-material-ui/
import { withTheme } from 'react-jsonschema-form';
import { Theme as MuiTheme } from 'rjsf-material-ui';
const Form = withTheme(MuiTheme);
If you want use component in material UI i did like this...
import material UI
import TextField from '#material-ui/core/TextField'
declare constant and costum widgets
const MyCustomWidget = props => {
return (
<TextField
type="text"
label="Name1"
value={props.value}
onChange={event => props.onChange(event.target.value)}
margin="normal"
/>
)
}
const widgets = {
TextWidget: MyCustomWidget,
}
and in the return of my component
return (
<div>
{' '}
<Form schema={schema1} widgets={widgets} >
{/* this is for disable the button Submit of Form */}{' '}
</Form>
</div>
It works for me
Weird to see there's no answer.
Quick answer: you cant!
Check out project's FAQ about that, it says:
Q: Will react-jsonschema-form support Material, Ant-Design, Foundation, or [some other specific widget library or frontend style]?
A: Probably not. We use Bootstrap v3 and it works fine for our needs. We would like for react-jsonschema-form to support other frameworks, we just don't want to support them ourselves. Ideally, these frontend styles could be added to react-jsonschema-form with a third-party library.
But! ... :) don't go so fast!
The closest I have come to achieve a Material "look and feel" was to use a Bootstrap Theme, Paper by Bootswatch which is quite nice!
Hope this helps anyone

Resources