Proposal improve of look and feel of Juce's applications

Whatever is done, it should probably be in a bundle. Something like JUCE_Css.

I hadn’t thought about this, but holy cow are you right. Debugging CSS is already pretty ugly, but this would be a nightmare.

A pretty easy solution would be to extend AudioPluginHost and have it set up a local server which returns a non-interactive raw html/css version of the current state of the plugin.

You could debug ui like so:

  1. Navigate your plugin to the broken view
  2. Refresh your browser at (localhost::[AUDIO_PLUGIN_HOST_SERVER_PORT])
  3. The plugin renders a non interactive dom and appends all plugin css
    • Basically just get the components to return a DOM of <div class="myClassNames" id="myId">
  4. Then figure out which css is the problem, update it, recompile and start over
    • (Bonus points) the plugin watches the css for updates and does it without recompiling

Practically no overheard, and the only assumption is that the developer has a browser (with dev tools).

So, maybe we should get started. Is anyone else interested in finding an open source CSS/Dom rendering library and creating a

#import "SomeOpenSourceCssLibrary.h"

class CssComponent
  : public JUCE::Component,
    public SomeOpenCssLib::DomElement

I’d really love to work on this project, but not alone.

I’m thinking the first step is to find a solid FOSS Css/Dom library. Anyone got a lead on that?

EDIT: for anyone who’d rather not use CSS/Dom, that’s fine. But I’d still like to work on it, with others. As long as they’re modules, JUCE can have more than one rendering style.

EDIT: I’m currently in contact with the slack channel for It’s not a perfectly FOSS solution, but ASFAICT it’s the best mostly open source css/dom rendering library out there.

@daniel Fwiw, I was just making a general comment about these kinds of systems, nothing specific to your implementation. :slight_smile:

Alright. After doing some research, it ends up there is no open source bare-bones css/dom rendering code base out there.

LibRocket was close, but it’s 2 years dead.

Ultralight has all the right functionality, but after talking to the dev it’s become apparent that it’s behind a closed source wall. Another perfectly good project made useless by greed.

From there, the best I could find is the WebCore section of webkit. A solid starting point would be Node.h ( It doesn’t look too bloated in terms of what it does. Things like shadowRoot and documentFragment functionality are totally unnecessary, but the rest of it seems essential.

I also found this old but still accurate blog on using WebCore:

Also, regarding layout, a widely used library is (used in React Native)

From my experience using React Native, a simple declarative XML to represent the component tree, along with stylesheets (not cascading), works really well. Basically, each component has a set of “style” attributes which it can respond to; basic ones such as backgroundColour, width etc as well as component-specific attributes.

With a system like that it becomes very quick to re-style components. The current JUCE LookAndFeel system can feel very cumbersome in comparison.

My opinion: I don’t see a need to recreate CSS here, I often found CSS overly complex and confusing to use in my web development days. I think JSON or dictionary objects to represent styles would be sufficient.

Something like this? (a simplified example from React Native translated into C++)

typedef std::map<String,std::map<String,var>> StyleSheet;

struct StyledComponent : public Component
	StyleSheet styles =
				{"borderRadius", 4},
				{"borderWidth", 0.5f},
				{"borderColor", "#d6d7da"}

				{"fontSize", 19},
				{"fontWeight", "bold"}

	String layoutXml = R"(
	<ContainerComponent styles="container">
      <Label styles="title"/>

If preferred, the layout could be imported from an XML file, and the stylesheet from e.g. a JSON/TOML file.


But I still suggest the StyleSheets syntax to be able to use an existing standard, with an optional “style” tag to define/override parameters directly in the XML.

    String layoutXml = R"(
	<ContainerComponent id="container">
      <Label id="title" style="font-family: 'Times New Roman', Times, serif;"/>

I agree with the data structure, I would only add two methods: one to import from JSON and one from CSS (without the cascading) which is a bit less verbose and great for quick inline definitions.

typedef std::map<String,var> Style;
typedef std::map<String,Style> StyleSheet;

struct Layout {
    StyleSheet styleSheet;
    void setLayout(String xml);
    Style &getStyle(String id);

struct StyledComponent : public Component{
    Style style;
    void setStyleJSON(String json);
    void setStyleCSS(String css);
    var getStyleProperty(String propertyName);

In terms of propertyName, there is room for implementing them progressively (actually not all of them make sense in every Component) but we could use as a reference those marked in green as a W3C Recommendation (REC) in the CSS standard:
(There are 148 properties in total in green, and I think that those which relate to speech, video or audio can be safely ignored, leaving 116 that are relevant)

Isn’t it ironic, that this page has layout problems? :rofl:

1 Like

Well you clearly don’t remember or didn’t have the chance to enjoy the great days of Mozilla and Internet Explorer, not to mention the wonders of Flash. Websites would even show up blank if you were using the wrong browser or operating system. Actually at that time, designers wouldn’t even know CSS, all they knew was Flash so all I’m saying is let’s build on that progress…

That was no criticism on the achievements of CSS and web technology. I do remember this non-standard enhancements, the battle of political influence over things like round corners and other behaviour. The fights between IE and Netscape Navigator, in fact, I wrote my first website in 1998.

But I avoid web design for exactly that reason, because you are constantly fixing other peoples bugs or working around their “features”. I don’t miss it, and my hair stands up, when I have to touch that.

But I follow the argument, that it would be good to use technology, that people are already familiar with, that’s why I agree a layout and styling system should adapt as much as possible the CSS/DOM approach.

So you went for plugins :wink:


Haha, indeed… not much different in some regards :wink:


I agree with the extra methods you suggest. However, I still disagree about using CSS. CSS is a web standard; it needs to be a standard for web browsers to be able to render HTML layouts in a consistent way. I see no reason to follow that standard to the tee when writing a styling engine for JUCE.

e.g. font-family: 'Times New Roman', Times, serif; - there is a lot to implement just in that small piece of inline styling. And it is not clear what it does, unless you already know CSS. Why not just give a font name? And why use dash-case when everything else in JUCE is camelCase? I have to say, it’s one of the things I really like about React Native: that they did not re-invent CSS, but took the idea, and simplified it to a level that is easy and intuitive to use, e.g.

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  title: {
    fontSize: 25,
    fontWeight: 'bold',

As @daniel also mentioned, QML is another nice example of styling for native applications.

On that note, a very cool project to check out is - he used embedded Ruby (mruby) and an adaptation of QML to build a plugin UI.

1 Like

I get your point, but those are all arguments from a coder’s perspective and I insist once again that the only reason that I have to propose CSS is because I don’t find a reason to teach the designers another set of tags, write a reference for that or even more challenging: making them read it, so I find it irrelevant that JUCE uses camelCase. PS. Do you think it is possible to make a designer respect the camelCase convention? :face_with_raised_eyebrow:

CSS is terrible ( but can we really change it now? I mean if you can convince me that there is another way to effectively communicate with graphic artists I’m all for it.

The font-family line might be a PITA to implement but it says: I’d like the ‘Times New Roman’ font but if you don’t have it your system, use ‘Times’ and if you don’t have this one either, just use one in the serif family. It solves a very real situation where you don’t want or you can’t embed the font that you want in your plugin.

Still, there is not need to fully implement CSS, we can definitely agree on a small subset of properties with single values.

Ok, I guess we have different use cases; the only designers I know tend to avoid any form of code, or maybe know a little HTML/CSS, but generally, I’m the one implementing their designs from PSD/SVG files. I don’t expect designers to touch my styling code; my aim is to reduce the friction in styling JUCE components, and make it quick and painless to try out and adjust styles and layouts.

1 Like

Ok, here’s another proposal. And if we allow for multiple sets of property names to coexist by agreeing on a minimal set of “standard JUCE tags”?

I came out with the following code where, after declaring the property names that you deem to be better suited to your use case, you can change:

#define StyleSyntax CSS

and let’s say set it to your QML list of properties:

#define StyleSyntax QML

The syntax is defined in compile time, the properties accessed in O(log(N)) and the getters and setters for each property are defined in the same place with lambdas. It also allows you to declare your own non-compatible properties in your custom Components. I welcome your suggestions to improve the code.

enum StyleIds {

const String CSS[numStyleIds] = {
  "background-color", //backgroundColourId,
  "border-bottom-color", //borderBottomColourId,
  "border-bottom-width", //borderBottomWidthId,
  "border-left-color", //borderLeftColourId,
  "border-left-width", //borderLeftWidthId,
  "border-right-color", //borderRightColourId,
  "border-right-width", //borderRightWidthId,
  "border-top-color", //borderTopColourId,
  "border-top-width", //borderToptWidthId,
  "outline-color", //outlineColourId,
  "outline-width", //outlineWidthId,
  "caret-color", //caretColourId,
  "cursor", //cursorId,
  "direction", //directionId,
  "font-family", //fontFamilyId,
  "font-kerning", //fontKerningId,
  "font-size", //fontSizeId,
  "font-style", //fontStyleId,
  "color", //textColourId,
  "color", //colourId,
  "font-weight", //fontWeightId,
  "left", //xId,
  "top", //yId,
  "height", //heightId,
  "width", //widthId,
  "margin-bottom", //marginBottomId,
  "margin-left", //marginLeftId,
  "margin-right", //marginRightId,
  "margin-top", //marginTopId,
  "opacity", //opacityId,
  "padding-bottom", //paddingBottomId,
  "padding-left", //paddingLeftId,
  "padding-right", //paddingRightId,
  "padding-top", //paddingTopId,
  "text-align", //horizontalAlignId,
  "vertical-algin", //verticalAlignId,
  "z-index" //zIndexId

//change this line to compile with a different syntax
#define StyleSyntax CSS  

  #define logError(errorString){ Logger::writeToLog(errorString); }
  #define logError(errorString){}

//list of fonts available in the system
const StringArray SYSTEM_TYPEFACE_NAMES=Font::findAllTypefaceNames();

static Colour parseColour(const String &str){
  String colourStr(str.fromFirstOccurrenceOf("#",false,false));
  if (colourStr.isEmpty())
  if (colourStr.length()==6) //alpha missing
  return Colour(colourStr.getHexValue32());

static String removeInvisibleChars(const String &str) {
  int start=0;
  while (start<str.length() && (str[start]==' ' || str[start]=='\n' || str[start]=='\r' || str[start]=='\t' )) start++;
  int end=str.length()-1;
  while (end>0 && (str[start]==' ' || str[start]=='\n' || str[start]=='\r' || str[start]=='\t' )) end--;
  return str.substring(start,end+1);

static bool isStringOnlyNumeric(const String &str )
    if (str.length() == String(str.getFloatValue()).length())
      return true;

    return false;

class Styled {    
  typedef std::function<void(const var&)> Setter;
  typedef std::function<var()> Getter;
  typedef std::pair<Setter,Getter> PropertyMethods;
  typedef std::map<String, PropertyMethods> Style;  

  Styled(Style &style,const String &name=String()): name(name),style(style){}
  virtual ~Styled(){}   

  bool hasProperty(const String &propertyName) {
    return (style.find(propertyName)!=style.end());

  String getSupportedProperties() {
    String keys="";
    for (auto it : style) {
    return keys.substring(0,keys.length()-1);

  void setProperty(const String &property, const var &value) {
    auto it=style.find(property);
    if (it!=style.end()){
    } else {
      logError("setProperty error: '"+String(property)+ "' is not a supported property in component '"+name+"'")

  void setProperty(StyleIds propertyId,const var &value) {

  var getProperty(const String &property) {
    auto it=style.find(property);
    if (it!=style.end()){
      return it->second.second();
    } else {
      logError("getProperty error: '"+String(property)+ "' is not a supported property in component '"+name+"'")
      return var::null;

  var getProperty(StyleIds propertyId) {
    return getProperty(StyleSyntax[propertyId]);

  virtual void styleChanged(const String &styleStr){}

  bool setStyle(const String &styleStr, bool callStyleChanged=true) {
    bool error=false;
    StringArray attributeList;
    for (auto attribute : attributeList) {
      if (removeInvisibleChars(attribute).isNotEmpty()){
        StringArray fields;
        if (fields.size()==2){
        } else {
          logError("style error: wrong format '"+attribute+"' in Component '"+name+"'")
    if (callStyleChanged)
    return error;
  const String name;
  Style &style;

class StyledLabel :  public Label,
                     public Styled{  

  Style style = {
    {StyleSyntax[StyleIds::fontFamilyId], PropertyMethods(
      [this](const var &value){
        //sets the font to the first typeface available in this system
        StringArray typefaceList;
        String listOfFamilies=value.toString();
        for (auto typeface:typefaceList){
          if (SYSTEM_TYPEFACE_NAMES.contains(removeInvisibleChars(typeface),true)){
            //get the lower and upper cases right
        //check if the fontStyle is valid with the chosen font family
        if (fontStyle.isNotEmpty()) {
          StringArray systemStyles=juce::Font::findAllTypefaceStyles(fontFamily);          
          if (systemStyles.contains(fontStyle,true)){
            //get the lower and upper cases right
          else {
            logError("Label '"+getName()+"' with font-family "+fontFamily+" has not the following style available: "+fontStyle);
        return var(fontFamily);
    {StyleSyntax[StyleIds::fontSizeId], PropertyMethods(
      [this](const var &value){
        String sizeStr=value.toString();

        if (sizeStr.endsWith("pt")) {
          if (isStringOnlyNumeric(sizeStr)) {
          } else {
            logError("Label '"+getName()+"' has a font-size with wrong format: "+sizeStr);

        } else if (sizeStr.endsWith("px")) {
          if (isStringOnlyNumeric(sizeStr)) {
          }  else {
            logError("Label '"+getName()+"' has a font-size with wrong format: "+sizeStr);

        } else {
          if (isStringOnlyNumeric(sizeStr)) {
          } else {
            logError("Label '"+getName()+"' has a font-size with wrong format: "+sizeStr);
        return var(String(fontSize)+String((fontSizeIsInPt)? "pt":"px"));
    {StyleSyntax[StyleIds::fontStyleId], PropertyMethods(
      [this](const var &value){                    
        /* this is not the implementation of the CSS font-style
           because in CSS font-style only indicates italics 
           (font-weight is used for bold)
           but this implements what both JUCE and most graphic tools mean by style

        if (fontFamily.isNotEmpty()) {
          //if the typefaceName is already set, check if it is a valid style

          StringArray systemStyles=juce::Font::findAllTypefaceStyles(fontFamily);
          if (systemStyles.contains(fontStyle,true)){
            //get the lower and upper cases right
          else {
            logError("Label '"+getName()+"' with font-family "+fontFamily+" has not the following style available: "+fontStyle); 
        return var(fontStyle);
    {StyleSyntax[StyleIds::textColourId], PropertyMethods(
      [this](const var &value){
        return var("#"+String::toHexString((int)fontColor.getARGB()));
    {StyleSyntax[StyleIds::horizontalAlignId], PropertyMethods(
      [this](const var &value){
        String str=value.toString().toLowerCase();
        if (str == "center") {
        } else if (str == "left") {
        } else if (str == "right") {
        } else if (str == "justify") {
          //A label only displays 1 line of text, so it can't really justify anything
        if (justification==Justification::centredTop) {
          return var("center");
        } else if (justification==Justification::topLeft) {
          return var("left");
        } else if (justification==Justification::topRight) {
          return var("right");
        return var("center");

  void updateFont() {
    if (fontFamily.isNotEmpty()) font.setTypefaceName(fontFamily);
    if (fontStyle.isNotEmpty()) font.setTypefaceStyle(fontStyle);

    if (fontSizeIsInPt)

  StyledLabel (const String& name, const String& labelText)
    : Label(name,labelText), Styled (style){

    Font font;
    Colour fontColor=Colours::black;    
    String fontFamily="";
    String fontStyle="";
    float fontSize=12;
    bool fontSizeIsInPt=true;
    Justification justification;


StyledLabel label;

// backwards compatibility

/* using Strings to refer to the properties 
   with property names that can be set to match the syntax in your style files
  (for faster parsing) */

// or if you prefer to set multiple properties at once

EDIT: std::map could be replaced by std::unordered_map which is a hash table that should give you O(1) access with a good hash function, but since the list of properties is rather short it is probably not worth it.


That’s pretty detailed! I’ll have to have a play with it when I have time, but seems like a good approach. I still like the idea of setting up a style object rather than parsing text (type errors can be caught at compile time), although I think both approaches are valid.

This wasn’t done by React, it’s vanilla js. (CSS Properties Reference - CSS: Cascading Style Sheets | MDN)

I like this, but really think it should be part of a module. Ultimately, while I do see this path leading to easier UI in the short term, it will inherently always fall short of modern UI design.

If we want to be able to make modern looking UIs, we’ll need to use libraries that keep up with that ability on their own. The two big libraries I’ve seen are the WebCore section of Webkit, and possibly Qt. If either of those can be made into a graphics module, it’ll basically mean lifetime support of the cutting edge in UI design practices.

But, once again, for the short term I think your proposal is great.

1 Like

I’ve edited again my last post (final proposal). I’m using this already for production with my custom components and it is working really well (it doesn’t slow down the user interface and it has simplified a lot my UI settings). I can’t spend more time with this but if anybody wants to build on top of it, take it (consider it released with MIT license).

1 Like

I’m a bit late to the party, so bear with me if I missed something that was posted years ago.

According to my experience, the first step towards being able to make “modern looking UIs” is to understand what makes a look “modern” in the first place. After all, the ingredients are simple (even got much simpler with current flat looks) and all it takes is to understand the visual idioms of UI design. No code can help you with that. And once you understand the desired look, any code will do.

So whatever latest buzzword technology is used, it won’t make anything look “modern” by itself. The focus should be solely on workflow: What makes the development and design cycle easier?

For me, CSS isn’t the answer. I’d rather like to see a protocol first, for setting layout and design properties on all components uniformly. This protocol may lean on CSS concepts, but needs not necessarily translate to CSS syntax. With a proper protocol in place, any external representation could be used.


Take a look at the « Styled » class code that I posted and feel free to criticize!