Theming
Puck is being deployed in a wide variety of situations that require different themes. We should support theming to support this.
Some ideas:
- classNames for everything that can be customised
- style tags for everything that can be customised
- a discrete API exposing a limited subset of style overrides
- custom render functions to enable users to take ownership of specific parts of the application
- remove CSS modules and expose all existing CSS classes
Let's have a discussion and form this into a more fully fledged series of proposals.
Related #122
Hi @chrisvxd !
I definitely support using custom properties. A great example of a similar implementation is shadcn (reference: CSS variables).
I use Tailwind CSS and would love it if the theme customization could be easily extended to Custom Fields or Plugins in my projects.
I think if you want to appease everyone you're probably going to need both inline style and className support.
And just to throw an extra complication into the works, there'll be people using styled-components that would like to be able to wrap your existing components instead of applying global styles. This might be able to be achieved in a similar way to how react-markdown allows customizing elements....
If you had an interface that allowed overriding/extending the styles in one place (in addition to style and className on each component) it'd be incredibly powerful. E.g.
noIdeaWhatToCallThis: {
Button: (ExistingComponent) => ({className, props}) => (
<ExistingComponent {...props} className={classNames(className, 'extra')} />
),
// Styled component example
Button: (ExistingComponent) => styled(ExistingComponent)`color: red;`
}
@Leweyse also a big fan of custom properties, so there could be something here. This might be a good way of doing a relatively light and controlled custom theming layer.
@JakeSidSmith I think what you're suggesting is the "custom render functions" option combined with "classNames", which is full UI override.
This is definitely the most powerful option and would allow people to do whatever they want, but I have concerns around the trade-off in making the internals part of a public API. If you remove a component internally, you now have to issue a breaking change. I imagine the risk of this happening decreases as Puck becomes more stable.
I agree with the simple solution with custom properties. They are well-known and supported and they can cover a lot of use-cases. Custom render functions would be for complete white-labelling, which is way to advanced (and heavily paid in solutions like Builder.io).
Initial pass being worked on by @Leweyse (see #175)
I think #224 may unlock this work, and should probably be a blocker here.
Hi everybody, until there is a theming option, here is the simplest workaround how to change the look and feel of your app:
- Copy the index.css file from the node_modules/@measured/puck/dist/ somewhere in your project: e.g., ./assets/css/index.css
- Import it as usual in your .tsx/.jsx/.js file: import "./assets/css/index.css";
- Adjust the styling to your needs
By the way, a big thank you to you for this library, it's easy to use and works perfectly. Great job Cheerio!
Would there be any interest in integrating with Skeleton for a theme system?
V3 is now in beta and they're bringing in official react support with this version, they make a lot of things look incredible by default it's definitely worth looking into.
@DevOfManyThings we're more likely to continue with our own implementation. We have an approach, but just haven't managed to prioritise this.
We have an approach, but just haven't managed to prioritise this.
Out of curiosity, what's the approach? I have a solution in place in one of my projects where I have a babel transformer going over Puck's published source, and looking for css modules. When it finds one, it essentially modifies the object;
From something like:
var styles_module_default18 = { "PuckPreview": "classNameForPuckPreview" };
To something like:
import { getInjectedStyles } from './customStyles'; // contains tools for setting styles for a specific component.
var old_css_module_default18 = { "PuckPreview": "classNameForPuckPreview" };
var styles_module_default18 = getInjectedStyles('Puck/components/Preview', old_css_module_default18);
And then re-publishes Puck (privately). I can then consume it in my real project. It works well, and let's me customize the specific parts I wanted to customize. And I fully expect to throw away this stopgap, once something like this lands.
Upvoting this one 🥇
As a tailwind v4 user, would love to learn more about how to integrate it!
FWIW I think the answer is css-variables.
do we need help on this one?
Thanks for your patience all. We're not looking for support, and know how to do this, but we've held off implementing this until the Puck UI stabilises to avoid introducing a new vector for breaking API changes.
Things are improving on that front, but we're not quite there yet. Please continue to hold🙏