react-modern-calendar-datepicker
react-modern-calendar-datepicker copied to clipboard
Themability: Color & Arrow
Is your feature request related to a problem? Please describe. I'd like to be able to easily change the color scheme of the component and swap the arrow icon.
Describe the solution you'd like Set key colors through props. Use these as CSS variables throughout the component.
Describe alternatives you've considered I can override most colors with classes and CSS selectors, but not for every element (e.g. arrow). Some colors are defined with CSS variables, which makes theming easy, others are 'hardcoded'. Sometimes I need to do some 'digging'.
Additional context I'll open a pull-request, where I've made some smaller tweaks to allow color theming (heavier use of CSS variables, additional props). This is not super complete, though. Also I am not a dev, so please be critical :)
Thanks for this beautiful component, I've wrapped it for Framer X so people can use it for prototyping: https://packages.framer.com/package/richy/modern-calendar Intend
Hi Richard, thank you so much for publishing this for Framer X. It's recommended to discuss the features here and then on a pull request. The changes you want to apply like changing the arrow are really vast. I think instead of implementing dozens of props for customizing one little thing, it's better to have a nice API for theming with some default themes like light
or dark
.
You're welcome, thank you for building this!
Regarding the API: I see, that makes sense. Maybe instead of adding a prop for each color, …
- having the option to override the CSS color variables directly through a custom class might be a better way, or …
- one
theme
prop, that can either be a preset likedark
andlight
or an object with all color definitions.
Anyways, my prototyping use case is probably quite atypical, so don't worry too much about it.
I think the second option is way better. I need others opinion about this API 🤔 I gotta pin this issue.
Hi there! I really need to change the arrow as well, has been any development on this? Or maybe there's a workaround in the meantime? :thinking: Like @richardbruskowski said, one can get by overriding classes, but I had no luck with the arrows :confused:
Hi @alessandrojcm, I need more feedbacks to make a decision about the full customizability API 🤔 Arrows are placed into the calendar using background-image
. Therefore, for now, you can override the default arrows by overriding the background-image
for .Calendar__monthArrow
CSS class:
Hi @Kiarash-Z, yes that was I was trying to do; but in our project we're using font awesome for the icons. Those are font icons, so I'm not sure how could I override the calendar's arrow with those. I've tried by setting the content
property in the ::after
pseudo-class and applying the font awesome classes with @extend
, but no luck :confused:
Regarding the API, I think that having an object which defines the theme would work; something among the lines of ThemeUI or TailwindCSS, where you defined all the variables in an object, then that could be applied via CSS custom properties. Now, with the arrow, I think render props could work: the calendar would pass a callback to the render prop that triggers next/previous date and then the user could just use whatever component they like; also, if you go with the theme object, the render prop could pass also the color variables. What do you think?
@alessandrojcm Yeah, I think this type of config might be good:
const getConfig = (defaultValues) => {
textColor: defaultValues.defaultColor,
// many other properties here...
renderArrows: (position) => <i className={position === 'left' ? 'left' : 'right'} />
}
<Calendar configure={getConfig} />
Or I might just define a separate prop for rendering arrows 🤔
@Kiarash-Z Yeah I agree, arrows should be a different prop. With the render props approach, I mentioned could look like this:
<Calendar>
{({ prevMonth, prevStyles }, { nextMonth, nextStyles }) => (
<CustomLeftArrow callback={prevMonth} className={prevStyles} />
<CustomRightArrow callback={nextMonth} className={nextStyles} />
)}
</Calendar>
Pros are that the user has full control of what to render, cons are that you couldn't get to fancy with the animations, you could pass the animations via the styles, but it would be up to the user to have the animations play nicely with their components. Also, there is the problem of the month/year selector: it should be rendered between the arrows render props make that difficult, you either pass the component as a prop, so the user is responsible for placing it; or you could place it yourself between the custom arrows (maybe using the classes for that, but then the user should pass the classes to the arrows.
Another approach I've seen in other libraries is, like you said, exposing props for the arrows:
<Calendar rightArrow={CustomArrowComponent} leftArrow={CustomArrowComponent} />
Those custom components should receive a callback as prop and the calendar would render that and pass the callback. What do you think? 🤔
@alessandrojcm This is a good approach but for rendering arrows. For the styles, I guess it's the developer's duty to provide appropriate styles when customizing arrows. For rendering arrows, I think it's kind of verbose to expose two props; one for each arrow. Therefore, I would rather pass an isLeft: boolean
to renderArrows
prop. It could look like this:
const renderArrows = ({ isLeftArrow, goToPreviousMonth, goToNextMonth }) => {
if (isLeftArrow) return <CustomLeftArrow className="MyCustomLeftArrow" onClick={goToPreviousMonth} />
return <CustomRightArrow className="className="MyCustomRightArrow" onClick={goToNextMonth} />
}
<Calendar renderArrows={renderArrows} />
I would be glad to hear your ideas 😊
@Kiarash-Z 5 Yeah that would work but, for me at least, passing a component to render both the arrows is kinda strange. How will the calendar render the month/year selector internally?
As for the styles, yes you're right that the dev should be responsible for the styling. But passing at least the colors would be nice for the sake of consistency.
@alessandrojcm It's quite easy internally:
{renderArrows({ isLeftArrow: true })}
<MonthYearSelector />
{renderArrows({ isLeftArrow: false })}
As for the colors, I think because of their default color(black), it wouldn't be needed to expose them to renderArrows
function.
@Kiarash-Z oh, I see. Well, regarding the colors, I meant if the user passes a theme (in which the arrow color could change) I think it would be nice to pass that down to the arrows, just to be consistent 🤔
Any updates on the renderArrows
? I think it would be a great addition to the API, along with renderDay
and renderHeader
.
Hi Is there any possibility of changing the background color of the calendar right now?
@setayeshk you can set it through this css:
.custom-calendar { box-shadow: 0 1em 3em rgba(156, 136, 255,0.2); background-color: #040320; color: white; }
A temporary solution for now:
<Calendar
value={selectedDayRange}
onChange={setSelectedDayRange}
calendarClassName="custom-calendar"
calendarSelectedDayClassName="custom-selected"
calendarRangeStartClassName="custom-start"
calendarRangeBetweenClassName="custom-between"
calendarRangeEndClassName="custom-end"/>
.custom-calendar {
box-shadow: unset !important;
background-color: unset !important;
.Calendar__day, .Calendar__monthText, .Calendar__yearText {
color: white !important;
}
.custom-start, .custom-end, .custom-between {
color: white !important;
background-color: rgba(0, 128, 255, 0.7) !important;
}
.Calendar__monthArrow {
background-image: url("data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%2724%27 height=%2724%27 viewBox=%270 0 24 24%27%3E%3Cg class=%27nc-icon-wrapper%27 fill=%27%23ffffff%27%3E%3Cdefs stroke=%27none%27%3E%3C/defs%3E%3Cpath class=%27cls-1%27 d=%27M12 23.25V.75%27 fill=%27none%27 stroke=%27%23ffffff%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27 stroke-width=%271.5px%27%3E%3C/path%3E%3Cpath class=%27cls-2%27 d=%27M22.5 11.25L12 .75 1.5 11.25%27 fill=%27none%27 stroke=%27%23ffffff%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27 stroke-width=%271.5px%27 fill-rule=%27evenodd%27%3E%3C/path%3E%3C/g%3E%3C/svg%3E") !important;
}
.Calendar__monthYear.-shown>*:hover, .Calendar:not(.-noFocusOutline) .Calendar__monthYear.-shown>*:focus, .Calendar__monthYear>*.-activeBackground {
background: #f5f5f577 !important;
}
.Calendar__day:not(.-blank):not(.-selectedStart):not(.-selectedEnd):not(.-selectedBetween):not(.-selected):hover {
background: #eaeaea77 !important;
}
.Calendar__day.-today:not(.-selectedStart):not(.-selectedEnd):not(.-selectedBetween)::after {
background: white !important;
}
.Calendar__yearSelectorWrapper::after, .Calendar__yearSelectorWrapper::before {
visibility: hidden !important;
}
.Calendar__yearSelectorItem.-active *, .Calendar__monthSelectorItem.-active * {
background-color: rgba(0, 128, 255, 0.7) !important;
}
}