puck icon indicating copy to clipboard operation
puck copied to clipboard

Theming

Open chrisvxd opened this issue 2 years ago • 15 comments

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

chrisvxd avatar Oct 06 '23 15:10 chrisvxd

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.

leweyse avatar Oct 06 '23 20:10 leweyse

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;`
}

JakeSidSmith avatar Oct 07 '23 23:10 JakeSidSmith

@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.

chrisvxd avatar Oct 10 '23 11:10 chrisvxd

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).

BleedingDev avatar Oct 22 '23 16:10 BleedingDev

Initial pass being worked on by @Leweyse (see #175)

chrisvxd avatar Nov 01 '23 18:11 chrisvxd

I think #224 may unlock this work, and should probably be a blocker here.

chrisvxd avatar Nov 21 '23 13:11 chrisvxd

Hi everybody, until there is a theming option, here is the simplest workaround how to change the look and feel of your app:

  1. Copy the index.css file from the node_modules/@measured/puck/dist/ somewhere in your project: e.g., ./assets/css/index.css
  2. Import it as usual in your .tsx/.jsx/.js file: import "./assets/css/index.css";
  3. 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!

BehnamKaraj avatar Sep 29 '24 07:09 BehnamKaraj

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 avatar Nov 12 '24 12:11 DevOfManyThings

@DevOfManyThings we're more likely to continue with our own implementation. We have an approach, but just haven't managed to prioritise this.

chrisvxd avatar Nov 15 '24 09:11 chrisvxd

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.

Zn4rK avatar Nov 16 '24 17:11 Zn4rK

Upvoting this one 🥇

codercatdev avatar Feb 12 '25 01:02 codercatdev

As a tailwind v4 user, would love to learn more about how to integrate it!

austinm911 avatar Mar 11 '25 16:03 austinm911

FWIW I think the answer is css-variables.

tonioloewald avatar Jul 01 '25 09:07 tonioloewald

do we need help on this one?

greg-truewind avatar Aug 01 '25 23:08 greg-truewind

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🙏

chrisvxd avatar Aug 14 '25 14:08 chrisvxd