I have four classnames, lets call them red-0, red-1, blue-0, blue-1
The CSS for red-0 and red-1 is the same, and the CSS for blue-0 and blue-1 is the same.
My React component are changing the classNames just as I want. My problem is that it seems like the React component ignores the CSS styling when I apply a classname with the same CSS it had right before the state change. Is this an actual case? Because my CSS changes perfectly when it goes from e.g. red-0 to blue-0, but not from red-0 to red-1.
If you have a suggestion of how I can solve this problem, I would be greatful.
A buddy helped me:
The trix was to add a promise and first set the state to an empty classname, and then add the classname that i wanted inside the promise, like this:
this.setState({ className: '' }, () => this.setState({ className: 'red-0' }));
The reason for having four classnames instead of two was because I hoped the classname change would trigger a new animation, but it did not, even though it triggered new regular CSS changes. I ended up using only two classnames: red and blue
Related
I'm trying to utilize the Autocomplete component from React Material-UI in my Website and I've already managed to customize the appearance of the List-Elements to display with a dark background, as you can see in this image:
The problem is that I cannot figure out how to style the group-labels of this list. In this project, I have to use class-components so I cannot use a solution that uses React-Hooks. I guess I could somehow achieve it by overriding the CSS of this Component, but I can't figure out how.
I already tried solving this by using the createMuiTheme() function and overriding the MuiListSubheader styling, but sadly this also didn't work.
In the documentation I saw that the Autocomplete component has a "groupLabel" key within the "classes" prop, but for some reason I can only enter a string into this key.
I managed to style the list items by using the "PaperComponent" Prop of the Autocomplete component, but I couldn't find a similar solution for the list subheaders.
Thanks in advance for any help!
I managed to do it by passing a PopperComponent to the Autocomplete like so :
<Autocomplete PopperComponent={StyledPopper}></Autocomplete>
This StyledPopper is defined as such with MUI v5 styled components :
const StyledPopper = styled(Popper)(({ theme }) => ({
'& .MuiAutocomplete-groupLabel': {
backgroundColor: theme.palette.primary.main,
color: theme.palette.common.white,
},
}));
You can also style the paper in it with '& .MuiAutocomplete-paper'
I have seen a lot of threads on the topic, but nothing seems to work for me the way I want it. I have a React component which takes in className as a prop. I also have a HOC which takes in a component and default style, and returns a component which takes in a new style, as such:
function withCombinedStyles(WrappedComponent, defaultClassName) {
return ({className: newClassName, ...rest}) => {
const className = combineClassNames(newClassName, defaultClassName);
return <WrappedComponent className={className} {...rest} />;
};
};
Currently, combineClassNames just concatenates the strings. I want to make it so that the newClassName always overrides the clashing styles with the defaultClassName but keeps the old ones. Currently, one of the styles seems to override the other but without apparent order - it doesn't matter how I put defaultClassName and newClassName. How can I do that? Currently, I use CSS modules but the project is still small enough for me to be able to rewrite the styles with another technology if that would achieve the desired result and CSS modules cannot do that (though I would prefer to use CSS modules and a React-specific solution with them would work since).
I would use !important but that would mean that I can never add a third className and it could be challenging to extend the styling in the future.
If you were doing CSS in JS then the order would matter, but because you're just combining CSS class names what really matters is specificity. Say newClassName has declarations that are less specific than the ones in defaultClassName - then the more specific declarations in defaultClassName will win over. You can probably fix your CSS by just ensuring the statements you want to 'win' are more specific.
Check out calculators like this one
If you went with inline CSS-in-JS styles I think something like this might work:
function withCombinedStyles(WrappedComponent, defaultStyles) {
return ({styles: newStyles, ...rest}) => {
return <WrappedComponent style={{...defaultStyles, ...newStyles}} {...rest} />;
};
};
Check this out < my library, which effectively does .logo.logo under the hood, but in a neater way.
I have been creating a set of reusable components that I had been styling using classes prop to override the MUI classnames. I then extracted a lot of the common styling into a theme to avoid repetition in the more complex components. The theme is wrapping each of the components using the withTheme HOC.
I am now realising that there are places we need to override the style for one-off cases. I thought I should be able to do this using the withStyles HOC but it doesn't seem to work for me.
Codepen at https://codesandbox.io/s/overriding-a-withtheme-with-withstyle-hoc-0m9cm
MyReusableThemedComponent - is the reusable component (that is really just wrapping Material UI tabs with a theme)
CustomOverideTabs - is my implementation of the MyReusableThemedComponent where I am trying to override the Material-UI textTransform by making the text lower case.
const StyledTabs = withStyles({ root: { textTransform: "lowercase" } })(
MyReusableThemedComponent
);
I believe the transform: uppercase is the default for the MuiTab-root class, but even specifying it in the theme doesn't seem to make a difference.
TIA
The effect of withStyles is to inject a classes prop into the wrapped component (MyReusableThemedComponent in your case), but you aren't doing anything with that injected prop except passing the entire props object to useStyles during the creation of tabsStyle. This will merge the two sets of classes, but then you would need to leverage tabsStyle.root somewhere to have any effect.
You have the following code for rendering the Tab elements:
<Tab
key={index}
label={tab.tabTitle ? tab.tabTitle.toString() : "tab" + { index }}
disabled={tab.disabled}
classes={{
root: tabsStyle.tabRoot,
selected: tabsStyle.selectedTab
}}
/>
This is leveraging tabsStyle.tabRoot as the root class, but tabRoot hasn't been defined anywhere. The textTransform works as intended if you change this to root: tabsStyle.root, or if you leave the Tab rendering unchanged, you can get it to work by changing the rule name in your withStyles call to be tabRoot (e.g. withStyles({ tabRoot: { textTransform: "lowercase" } })).
Example using tabsStyle.tabRoot (i.e. only changing the withStyles argument): https://codesandbox.io/s/overriding-a-withtheme-with-withstyle-hoc-fxybe
Example using tabsStyle.root (i.e. only changing how the classes prop is specified when rendering the Tab elements): https://codesandbox.io/s/overriding-a-withtheme-with-withstyle-hoc-ptj87
A separate issue in your sandbox is that you appear to be trying to specify style overrides in the theme in ConditionalThemeWrapper, but the structure of the theme is incorrect. The MuiFab and MuiTab entries in the theme should be within an overrides key. Here is a modified version of your sandbox demonstrating this: https://codesandbox.io/s/overriding-a-withtheme-with-withstyle-hoc-ju296
Related documentation:
https://material-ui.com/customization/components/#global-theme-override
I am currently writing a component in svelte and in order to work on only this component I am also using storybook.
The problem is that because of the css library I am using the component will be incorrectly rendered unless it is properly wrapped by a parent element. In short, this component is list element and without the list wrapper the css will be funky.
So the question is, can I somehow tell storybook to wrap my component in a div?
i.e. something like this
storiesOf("Kanban card", module)
.add(
"small",
() => ({
Component: Card,
template: "<div class='wrapper'><Card /></div>",
props: {
...
}
})
);
Your best bet would be to create a separate Svelte component, specifically for that story. This approach also gives you a way to use slots properly, something that's not clearly available through Storybook.
Something like kanban-card.story.svelte containing:
<script>
import Card from '../wherever/kanban-card.svelte';
// export the props that the component needs
// pass up all events you want to handle
</script>
<Card on:eventYouWant />
I have a very niche use-case. I have to add a modal animation like this:
regular css animation
But I need to have a component (our own filter component for a datatable) inside said modal.
So I need to use the ModalService. But this service is only attaching my custom config like this:
toggleFilter = () => {
const modalOptions: ModalOptions = {
initialState: {
labels: this.datatableLabels, // needed for filter to have labels
filterGroups: this.filterGroups // needed to add filterGroups
},
class: 'filter-modal' // this sould be my custom class
};
this.bsModalRef = this.modalService.show(FilterComponent, modalOptions);
}
to modal-content and the above mentioned animation and styling uses divs above that. Not only it's working when encapsulation set toViewEncapsulation.None then it screws our other modals as well, since I cannot apply correct classes to the one I need to mess with.
How can I overcome this issue I'm having?
Instead of using the ModalService and open desired embedded component within the modal. You can basically inject the desired component into the body of the modal while using directive instead -> Here you are declaring the whole modal layout -> you can modify all the related classes so it's easier to modify a modal and have your ViewEncapsulation untuched so other modals are unaffected.