The
styledmethod works perfectly on all of your own or any third-party components as well, as long as they pass theclassNameprop to their rendered sub-components, which should pass it too, and so on. Ultimately, theclassNamemust be passed down the line to an actual DOM node for the styling to take any effect.
https://www.styled-components.com/docs/basics#styling-any-components.
It would be nice if all the components passed down className. I don't think styled-components is the only styling system that would benefit from this change. This would allow
const StyledDateRangePicker = styled(DateRangePicker)`
.CalendarDay{
background-color: red;
}
`;
If it is not possible, maybe that should be documented somewhere?
If this issue should be moved to https://github.com/airbnb/react-with-styles I can re-open it there.
className props shouldn't be passed down between components though - https://brigade.engineering/don-t-pass-css-classes-between-components-e9f7ab192785 is a good read on the subject.
If that's what's required to make styled-components work with third-party components, then styled-components may not be a good choice when using third-party components.
I've read the blog post, and I'm still not 100% sure I agree with the sentiment here. Developers have to be responsible for their own code complexity. By choosing to not pass down className, airbnb is choosing to make this library incompatible with https://github.com/styled-components/styled-components, a fairly popular styling library (14k+ stars today, 800 forks etc).
In my opinion, the blog post made a pretty weak argument against passing down className. Sure, it's good advice for a developer to consider the complexity he is introducing by having both a className and also some props that affect styling. I don't think you can take this argument to the extent of saying "3rd party libraries should be incompatible with styling solutions that rely on className being passed down".
I have a decently sized code base that has many custom and 3rd party components. In this entire code base I have a single CSS file in the entire repo and it's just to style the DateRangePicker I use from this repo. Since this is the only CSS file, it also required separate build steps to make sure it is bundled with the app properly.
This is related to this whole entire closed issue, but I've linked to a specific comment where @ethanresnick links to his 5 issues where he had trouble customizing styles as well.
https://github.com/airbnb/react-dates/issues/474#issuecomment-304585546
I also think that it would be really nice to have className, because I'm using styled components in every of my projects and there are a lot of out there using it too, I wanted to implement it in 2 of these but it's impossible and I needed to go for some more opened solutions like react-datepicker even if it's not perfect fit because I wanted to achieve almost same functionality as react-dates.
Let me look into styled-components a bit more and see what we can do on a system-wide level. It's a very popular library, and it'd be ideal if we'd be able to support consumers who use it.
In the mean-time, if you have specific overrides that you keep writing/using again and again, we're pretty open to adding prop-based styles to the component especially if it seems like something that would be leveraged by many people.
I think that my personal philosophy on not having className and style be allowed on components is less about considering the complexity of both className and style-related props on a component and more about trying to preserve explicit boundaries between layers of the component tree. Prop-based styles like noBorder or block or even something like the CustomizableCalendarDay component have explicit rules about what can be changed. That means that those can be taken into account as we evolve the internal structure of the library. A change to DOM structure to a component that allows for free-form styling via a className or style prop seems much more likely to break lots of people's usecases than the same change to a component that doesn't.
This philosophy, of course, drives our use of Aphrodite internally, but becomes a bit weird when looking at react-dates which by default ships with stylesheets (and therefore is already kind of a bit more free-form). I will think more deeply on this. There may be some opportunity to leverage the react-with-styles abstraction layer to allow for a styled-components based customization through that.
Just a head's up this isn't impossible to style the object it just has to have a layer of abstraction to a styled div you place the <DatePicker /> in.
quick examlpe:
const Wrapper = styled.div'
div {
input {
border: 1px solid ${({ theme: { morales } }) => morales};
border-radius: 100px;
text-align: center;
}
}
'
@ckeeney - have you found a solution for overriding air bnb dates css?
i am having the same problem dealing with singleDatePicker css.
@ASH-khan the solution @Caryyon gave is the best you will get for now. Here is his solution implemented in my codebase:
import 'react-dates/initialize';
import {DateRangePicker} from 'react-dates';
import 'react-dates/lib/css/_datepicker.css';
import React from 'react'
const StyledWrapper = styled.div`
.DateRangePickerInput {
border-radius: 4px;
overflow: hidden;
justify-content: space-around;
}
.DateInput {
width: 30%;
}
`;
const MyStyledDatePicker = () => (
<StyledWrapper>
<DateRangePicker {/*...your params here...*/} />
</StyledWrapper>
)
export default DateRangePickerWrapper;
@ckeeney - thank you so much!
import {Box} from 'grid-styled'
import {themeGet} from 'styled-system' . did't get this ?
please see my component
import 'react-dates/initialize';
import React, { Component } from 'react';
import { SingleDatePicker } from 'react-dates';
import 'react-dates/lib/css/_datepicker.css';
import moment from 'moment/moment';
import Utils from '../../utils/Utils';
import Calendar from '../icons/Calendar';
import Close from `'../icons/Close';`
import styled from 'styled-components';
// Date Picker styled component styling
const DatePickerWrapper = styled.div`
width: 100%;
`;
export default class SingleDatePickerComponent extends Component {
state = { };
onFocusChange = ({ focused }) => {
this.setState({ focused });
};
onDateChange = (a) => {
if (this.props.onDateChange && a) {
this.props.onDateChange(moment(a));
}
};
onClearDate = () => {
if (this.props.onClearDate) {
this.props.onClearDate();
}
};
render() {
const { focused } = this.state;
const { calKey, enableOutsideDays, isOutsideRange, value } = this.props;
return (
<DatePickerWrapper>
<SingleDatePicker
/* props here */
/>
</DatePickerWrapper>
);
}
}
the react-dates css i want to override are these classes:
.SingleDatePicker {
width: 100%;
}
.SingleDatePickerInput {
width: 100%;
}
.DateInput_input__focused {
width: 100%;
border-bottom: none !important;
}
.DateInput {
width: 100% !important;
}
.SingleDatePickerInput__withBorder {
border: none;
}
.DateInput_input__focused {
width: 100%;
border-bottom: 1px solid #ccc !important;
}
thanks
Hi! Just a heads up that you can do at least some of this with props! :)
Try setting block and noBorder to true on the SingleDatePicker.
Overriding the focus state will still require some work.
On Fri, May 11, 2018, 5:56 AM ISH-2015 notifications@github.com wrote:
@ckeeney https://github.com/ckeeney - thank you so much!
import {Box} from 'grid-styled'
import {themeGet} from 'styled-system' . did't get this ?please see my component
import 'react-dates/initialize';
import React, { Component } from 'react';
import { SingleDatePicker } from 'react-dates';
import 'react-dates/lib/css/_datepicker.css';
import moment from 'moment/moment';
import Utils from '../../utils/Utils';
import Calendar from '../icons/Calendar';
import Close from'../icons/Close';
import styled from 'styled-components';// Date Picker styled component styling
const DatePickerWrapper = styled.divwidth: 100%; >;
export default class SingleDatePickerComponent extends Component {
state = { };
onFocusChange = ({ focused }) => {
this.setState({ focused });
};
onDateChange = (a) => {
if (this.props.onDateChange && a) {
this.props.onDateChange(moment(a));
}
};
onClearDate = () => {
if (this.props.onClearDate) {
this.props.onClearDate();
}
};
render() {
const { focused } = this.state;
const { calKey, enableOutsideDays, isOutsideRange, value } = this.props;
return (
/* props here */
/>
);
}
}the react-dates css i want to override are these classes:
.SingleDatePicker {
width: 100%;
}.SingleDatePickerInput {
width: 100%;
}.DateInput_input__focused {
width: 100%;
border-bottom: none !important;
}.DateInput {
width: 100% !important;
}.SingleDatePickerInput__withBorder {
border: none;
}.DateInput_input__focused {
width: 100%;
border-bottom: 1px solid #ccc !important;
}thanks
—
You are receiving this because you commented.Reply to this email directly, view it on GitHub
https://github.com/airbnb/react-dates/issues/1030#issuecomment-388252494,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABUdtfn-i1HNdw49N67BDtI2277o2YuVks5txQvYgaJpZM4SIw7w
.
@ASH-khan styled-system and grid-styled are two libraries I happen to use. grid-styled exports a few styled-components supporting a flexbox layout and styled-system has helpers to create styled-components that use a theme. Neither are important to this example but just happened to be part of my codebase.
edit: My answer above got a bit popular so I edited it slightly to remove the outdated/unrelated code and use a functional component instead of a class component.
@ckeeney
got it!
thank you!
i fixed my issue and looking good for now.
waiting on @majapw to hear some good news about classNames.
What about injectGlobals from styled components to get rid of a single css file to style the date picker?
Netherless className support would be great (other CSS-in-JS libs use the same mechanism)
@kelkes there injectGlobal would probably work, it was only a personal preference to keep the styling of the date picker with the usage of the date picker. injectGlobal would most certainly work as well.
Check how material-UI provides this interoperability
@sibelius having issue with material ui withStyles can you provide an example
It's almost 2020 and nobody found a way to use styled-components without wrapper in a div?
@jpcmf tech debt on tech debt on tech debt.
Any updates on this at all ? - @kdave2 I also need an example for mui withStyles
Material-UI ("MUI") has a way to pass in classes and styles from outside via a CSS API: https://material-ui.com/system/basics/#all-inclusive
When you have a more complex component with sub- and sub-sub-components there are props where you then can pass in styles / classes further down that get applied.
Check the Chip for example (Chip is a pill component with a text and/or up to two icons)
https://material-ui.com/api/chip/
So there you have the "normal" styles being applied by the framework and then you can add styles on top from outside passed in as an object saying "apply this color red to the avatar when it is set as small" - does that explain it?
cc: @missbruni @kdave2
Hi, I use styled-components for custom react-dates in nextjs
icon: https://fontawesome.com/icons?d=gallery
import 'react-dates/initialize';
import React from 'react';
import styled from 'styled-components';
import { DayPickerRangeController } from 'react-dates';
import moment from 'moment';
const NavIcon = styled.div`
font-size: 1rem;
border-radius: 50%;
position: absolute;
top: 12px;
width: 35px;
height: 35px;
display: flex;
display: -webkit-flex;
align-items: center;
justify-content: center;
&:hover {
background: #f7f7f7;
}
&:active {
transform: scale(.92);
}
&.prev {
left: 12px;
}
&.next {
right: 12px;
}
`;
const WeekHeaderText = styled.div`
font-size: .8125rem;
text-align: center;
`;
const MonthCaption = styled.p`
font-size: 1rem;
font-weight: 400;
color: ${props => props.theme.colors.black};
`;
const Td = styled.td`
max-width: ${props => props.daySize}px;
max-height: ${props => props.daySize}px;
margin: 0;
padding: 0;
border-radius: ${props => props.selectedSpan ? 0 : '100%'};
cursor: ${props => props.isOutsideDay ? 'default' : 'pointer'};
outline: none;
text-align: center;
background: ${props => props.selectedSpan
? '#F7F7F7'
: props.selected
? props.theme.colors.primary
: 'inherit'};
color: ${props => props.blocked
? '#C7C7C7' : props.selected
? props.theme.colors.white
: props.theme.colors.black};
`;
const Day = styled.div`
font-size: .875rem;
box-shadow: border-box;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
display: flex;
display: -webkit-flex;
align-items: center;
justify-content: center;
flex-direction: column;
width: ${props => props.daySize}px;
height: ${props => props.daySize}px;
border: 1.5px solid transparent;
cursor: ${props => props.blocked || props.isOutsideDay ? 'default' : 'pointer'};
text-decoration: ${props => props.blocked ? 'line-through' : 'inherit'};
border-radius: 100%;
&:hover {
border: ${props => props.blocked || props.isOutsideDay
? 'none'
: `1.5px solid ${props.theme.colors.primary}`};
}
span {
font-weight: ${props => props.blocked ? 200 : 400};
}
`;
const PrevIcon = props => (
<NavIcon {...props} className='prev'>
<i className='far fa-chevron-left' />
</NavIcon>
);
const NextIcon = props => (
<NavIcon {...props} className='next'>
<i className='far fa-chevron-right' />
</NavIcon>
);
const RenderMonth = props => {
const { month } = props;
const isCurrentMonth = moment().format('MM-YYYY') == month.format('MM-YYYY');
return (
<MonthCaption>
{month.locale("en").format('MMMM YYYY')}
{"This month"}
</MonthCaption>
);
};
const RenderCalendarDay = (props) => {
const { day, daySize, isOutsideDay, modifiers, onDayClick } = props;
const selected = modifiers &&
(modifiers.has("selected-start") || modifiers.has("selected-end"));
const selectedSpan = modifiers &&
(modifiers.has("selected-span") || modifiers.has("hovered"));
const blocked = modifiers && (!modifiers.has("valid") && modifiers.has("blocked"));
const onClickDay = () => {
onDayClick(day);
};
// console.log(props);
return (
<Td
daySize={daySize}
selectedSpan={selectedSpan}
selected={selected}
blocked={blocked}
isOutsideDay={isOutsideDay}
onClick={onClickDay}
>
<Day
daySize={daySize}
blocked={blocked}
isOutsideDay={isOutsideDay}
>
<span>{day && day.format('D')}</span>
</Day>
</Td>
);
};
export default function DateRangePickerWrapper({
startDate,
endDate,
numberOfMonths = 2,
hideKeyboardShortcutsPanel = true,
daySize = 40,
monthFormat = 'MMMM YYYY',
renderCalendarDay,
focusedInput,
onDatesChange = () => { },
onFocusChange,
}) {
moment().locale("en");
return (
<DayPickerRangeController
hideKeyboardShortcutsPanel={hideKeyboardShortcutsPanel}
numberOfMonths={numberOfMonths}
monthFormat={monthFormat}
onDatesChange={onDatesChange}
onFocusChange={onFocusChange}
focusedInput={focusedInput}
startDate={startDate}
endDate={endDate}
navPrev={<PrevIcon />}
navNext={<NextIcon />}
daySize={daySize}
renderCalendarDay={props => renderCalendarDay ? renderCalendarDay(props) : <RenderCalendarDay {...props} />}
renderWeekHeaderElement={week => <WeekHeaderText>{week}</WeekHeaderText>}
renderMonthElement={props => <RenderMonth {...props} />}
/>
);
}

+1 waiting this feature
Most helpful comment
I've read the blog post, and I'm still not 100% sure I agree with the sentiment here. Developers have to be responsible for their own code complexity. By choosing to not pass down
className, airbnb is choosing to make this library incompatible with https://github.com/styled-components/styled-components, a fairly popular styling library (14k+ stars today, 800 forks etc).In my opinion, the blog post made a pretty weak argument against passing down
className. Sure, it's good advice for a developer to consider the complexity he is introducing by having both a className and also some props that affect styling. I don't think you can take this argument to the extent of saying "3rd party libraries should be incompatible with styling solutions that rely onclassNamebeing passed down".I have a decently sized code base that has many custom and 3rd party components. In this entire code base I have a single CSS file in the entire repo and it's just to style the
DateRangePickerI use from this repo. Since this is the only CSS file, it also required separate build steps to make sure it is bundled with the app properly.