blueprint
blueprint copied to clipboard
Support for CSS in JS / modular styling API
Reading through the FAQ : https://github.com/palantir/blueprint/wiki/Frequently-Asked-Questions Specifically Blueprint with a traditional global CSS stylesheet for a few reasons
I would like to argue against the reasons presented using typestyle as an example.
Tooling for inline styles is still pretty nascent, while Sass and Stylelint are wonderful tools we love using.
With TypeStyle you get to use TypeScript tooling for CSS just like you use TypeScript tooling for JSX for HTML.
Regular CSS is easier to for consumers override and theme
Note the case, e.g. You should't need to go into a CSS specificity war to customise components : https://github.com/palantir/blueprint/issues/184. With TypeStyle you just take a className in your props and use classes
to compose the final style. This is mentioned here : http://typestyle.io/#/core And demonstrated below (and you can play with it here : http://bit.ly/2fpylJl) :
const messageClass = style({
color: 'grey',
fontSize: '24px',
width: '100%'
});
const Message = (props:{className?:string,text:string}) => {
return (
<p className={classes(messageClass,props.className)}>{props.text}</p>
);
};
<div>
{/** Without customization */}
<Message text="Hello"/>
{/** With customization */}
<Message text="World" className={style({color:'red'})}/>
</div>
Note: Using className
like TypeStyle, gives you all the power of CSS, something that cannot be done with the style
attribute.
Hope that helps, this trick will work even without TypeStyle. This is definitely a learning area, and I present more reasons here as well http://typestyle.io/#/why :rose: :heart:
Another example where managing just with js would help, you wouldn't need to give this warning as the CSS can be generated on the fly
@basarat always a pleasure to hear your input and see what you're working on!
Let's say we do decide to use typestyle. Doesn't this essentially force all of our downstream consumers to also use typestyle? With meaningful class names removed, users couldn't write regular CSS that gets along well with Blueprint. I'd be a little concerned about forcing this on users
always a pleasure to hear your input and see what you're working on!
Mutual respect for all your OSS efforts as well :rose: :heart: and Thanks!
Doesn't this essentially force all of our downstream consumers to also use typestyle?
Not quite. Few reasons:
- Multiple TypeStyle versions will work fine (each creates and manages its own
style
tag). Consumers are free to use whatever they want and don't need to know if the lib internally uses TypeStyle. - TypeStyle is small (~1k). Probably smaller than the monolith CSS that needs to be included right now for a single component without additional work. With TypeStyle, consumer would include/require what component they need to and just get the CSS that is required.
With meaningful class names removed, users couldn't write regular CSS that gets along well with Blueprint
They can write regular CSS with their choice of classNames and they get to chose even the framework e.g. aphrodite or CSS modules and pass in the generated or hand-written classNames
More Notes
- I was just arguing against the core reasons mentioned in the FAQ. If the reason is there is no clear winner I would completely understand and its a reasonable choice :heart:
- Other CSS in JS options were not focused on TypeScript and that is the key differentiator.
- Current blueprint forced SASS down to consumer. I feel managing typestyle is simpler (biased opinion of course).
- Would be happy to have any palantir team as owners if that is a blocker for adoption.
Sass is pretty great and indeed there's no clear winner for CSS in JS yet, but a solution like TypeStyle is very much something we want to research in the near-ish future
Consider Styled Components please!
I saw in the readme that you are considering using tools for css generation, I really hope you will not move to css-modules or worst styled-components.
My arguments/opinions :
- sass is a standard, approved and used by the community, there is no winner yet in theses tools.
- theses tools will really improve your developper experience only, when you build the framework, but for us it will be a nightmare to understand how it works.
- Another tool to learn, heard of the javascript fatigue ? ;-)
- This make things almost impossible to understand for a designer
- Blueprint is also an awesome, pure css framework, it will break this.
When I fist saw blueprint I thought, "yet another react framework", but when I saw how you keep things simple, I though "Ahh finally some people think about the developers and designers that will use the tool everyday", "Finally developers that don't think only about the purity of their code, but also about the great things we will build with it". I seriously believe that blueprint is by far the best tool to build enterprise class web applications
I hope this (very opinionated) post will help you to take the right decision.
Cheers, Florian
I really love the blueprint library, but really hoping to see CSS in JS used here at some point so not having to add two stylesheets. Importing a component would bring its styles, and only its styles, in at a time. Is this on the roadmap? Thanks!
@graysonhicks CSS in JS is not "on the roadmap" because it amounts to a holistic rewrite of each component. it's a future consideration and certainly something we're discussing internally, but i wouldn't hold your breath.
Something to consider is following the way that MUI does things, which has changed a lot over time, but I think they have settled on a pretty decent approach:
- https://material-ui.com/customization/themes/
- https://material-ui.com/guides/typescript/
- https://material-ui.com/guides/interoperability/
Interesting set of libraries in this vein: https://theme-ui.com/
If at some point you are looking to revamp/rewrite blueprintjs components with CSS-in-JS ii suggest using styled-components and styled-system
If you added these it would be much easier to make blueprint "themeable".
theme.ui is great but import things you don't need as library authors from my point of view.
+1, styled-system has nailed it. Theme UI has been great to work with.
If it is useful to anyone, styled-components support styling of any component: https://styled-components.com/docs/basics#styling-any-component
import { Card } from '@blueprintjs/core';
import styled from 'styled-components';
const StyledCard = styled(Card)`
background-color: lightsteelblue;
`;
const MyComponent = () => (
<div>
{/* default */}
<Card>Blip blop dippeti doo</Card>
{/* modified */}
<StyledCard>Dippe dabbe hippeti hop</StyledCard>
</div>
);
The problem that remains, though, is that Blueprint components can't be used in isolation since they depend on a global stylesheet. I wonder if it would be possible (relatively easily) to create a stripped down version of the global stylesheet, which can be applied to a div
instead of the global dom? This could be applied with styled-components as well:
import styled from 'styled-components';
import { strippedStyles } from '@blueprintjs/core'; // raw text
const BlueprintWrapper = styled.div`
${strippedStyles}
`;
const MyModularComponent = () => (
<BlueprintWrapper>
{/* blueprint components */}
</BlueprintWrapper>
);
some thoughts on theming Blueprint from an original author of this library (I left the company in early 2019) who has recently attempted this himself in a non-Palantir codebase. apologies for length (my first github essay!) but i have a lot of thoughts here and this is possibly the most contentious feature request in this project, so buckle up.
import { strippedStyles } from '@blueprintjs/core';
@ViggoV this suggestion of strippedStyles
is spot on and we should be so lucky to live in such a world! something I think about a lot these days is reconciling the two flavors of CSS: layout and presentation. Blueprint was designed to provide both of these at the same time with such quality that you wouldn't need more, which works really well inside Palantir. what you are asking for is the isolated layout styles here so that a component will render correctly (display: flex
, etc) and allow you to bring your own presentation styles. sadly, that is not how Blueprint is built. (but that is how i would build it were I to restart today.)
(an aside: this layout/presentation dichotomy actually also applies to the list of components—Button
vs OverflowList
—and it's my hypothesis now that "what the people truly want" is a set of high-quality advanced layout components to which they can bring their own visuals. but that's for another library.)
so here are a few things you can do to customize Blueprint today:
change the Sass variables
changing the $pt-*
variables themselves is the most reliable way to tweak Blueprint to your needs. I say "tweak" because you're still beholden to the actual CSS of the various components. you can change values but not rules. you can change the hue of $blue3
and the size of $pt-button-height
, but you can't (happily) change the background gradient & hover logic of a button.
note that this approach requires compiling blueprint.scss
from source and involves one or two hoop-jumps. fortunately, I just packaged up a script i wrote for this as an npm package: https://github.com/giladgray/blueprint-sass-compile. see the repo for full instructions.
it's just CSS
the brute force approach is to simply write your own CSS in your own stylesheet and apply it on top of blueprint.css
. this is far and away the cheapest solution up-front but deeply frustrating to maintain in the long term.
the sanest way to do this is to add your own className
to components and style that. you can even combine it with the .bp3-*
class name for an extra level of specificity: .bp3-button.my-button
& <Button className="my-button" />
.
the ✨magic of CSS✨allows you to override/clobber any and all styles, although i can't promise it'll be fun. you're going to write some gross styles. your main enemy will be specificity because blueprint involves some highly specific CSS selectors. an appropriate use of !important
is to override external styles that you cannot edit yourself.
make your own Button
i suggest creating your own wrappers for common UI components like buttons, inputs, etc. This component does not need to be more complex than a wrapper for BP Button
; its purpose is to provide a single place for your customizations.
this pattern has another advantage: it isolates your codebase from UI kit implementation changes. if your entire app uses your own MyButton
then you could (in theory) swap the underlying Button
implementation without updating all your imports or usages!
here's a basic skeleton:
import { Button, IButtonProps } from '@blueprintjs/core';
import classNames from 'classnames';
import React from 'react';
export interface MyButtonProps extends IButtonProps {
// add custom props here
bold?: boolean;
}
// you can also totally use something like styled-components in here!
export const MyButton: React.FC<ButtonProps> = ({ bold, className, ...props }) => {
const classes = classNames('my-button', bold && 'my-button-bold', className);
return <Button {...props} className={classes} />;
};
MyButton.displayName = 'MyButton';
I can't speak for other people but in my case the problem is not really related with Blueprint Component behaviour. It's pretty easy in fact to override Blueprint component even using styled-components. Problems come when you try to build a new component for your project and you want to make him look alike blueprints one in terms of color or margin.
The real problem is that there only a few documentation and for example you can't know that a button minimal background hover is rgba($gray4, 0.3)
unless you look into sass code directly. For me styled-system theme would be enough but i'm not sure it's for everyone.
@giladgray Thank you for the detailed answer. If I understand you correctly it seems that you misunderstood me. In the strippedStyles
examples I am actually asking for both presentation and layout styles, but packed in such a way that it can be applied to a sub-element rather than globally. In terms of overriding presentation styles I think the different approaches are somewhat satisfying (override sass-vars, apply new class, wrap in styled-component etc.) and could probably be improved just by adding an overview of the css-properties of each component to the documentation.
The exact reason I was looking into this is that we are slowly working towards migrating our massive applications frontend to a react
(and presumably blueprint
) based solution. However, I am the sole frontender at this point so I replace different parts of the application with standalone modules when they need to be updated. Currently I can't use blueprint
for that since it would force me to inject global styles that would mess with the current layout/presentation.
I am sorry if this goes a little off the path for issue, but I was directed here after adding a new issue on the topic.
I am having some partial luck with a dirty, hackish solution. I import the raw contents of the global stylesheets and regex
out the html
and body
wrappers. I then use styled-components
to create a "style provider" wrapper, which unsets all other styles and include the contents of the Blueprint stylesheets under its generated class name:
import styled from 'styled-components';
import bp_css from '@blueprintjs/core/lib/css/blueprint.css';
const unwrap_rex = new RegExp('^(html|body)\s?{([^}]*)}', 'gms');
const unwrapped_bp_css = bp_css.replace(unwrap_rex, '$2');
// doing the same with the icons css and normalize
const StyleWrapper = styled.div`
*, *:before, *:after {
all: unset;
}
${unwrapped_bp_css};
`;
const MyIsolatedApp = () => (
<>
<h1>This is styled by the global styles</h1>
<StyledWrapper>
...everything in here has Blueprint styles
</StyledWrapper>
</>
);
The above does apply Blueprint styles within the wrapper as expected, but something is wrong with the box-model. Even though everything I've put in there has had display: block
, float: none
and box-sizing: border-box
applied according to Chrome devtools, everything is mashing together as shown below. The brown box contains the StyleWrapper with an
<H1>
and a <Card>
.

PS: sorry for the nasty "this is a test - do not use" styling
A lot has change in the React ecosystem since this issue was opened back in 2016. Specifically, React Server Components (RSC) are now a thing, which are being implemented in popular frameworks like Next.js. However, RSCs do not work with CSS-in-JS solutions (at least none that I'm currently aware of). As such, many UI component libraries are starting to move away from this approach in favor of purse CSS approaches that can be supported by server rendering. I think it would be prudent to consider this when evaluating a new approach for Blueprint.