Style with CSS

Blockly applications are constructed of HTML and SVG elements. These elements are labeled with CSS classes that identify what they represent (e.g. blocklyBlock, blocklyField) as well as their state (e.g. blocklyEditing, blocklySelected). Blockly also provides a default set of CSS rules.

You can use CSS to style your application:

  • Override Blockly's CSS rules with your own rules.
  • Add your own CSS classes to Blockly components for additional specificity.
  • Use CSS classes and rules to style custom components.

CSS classes

Blockly applications use CSS classes to identify elements to be styled. This provides finer-grained control than type (element) selectors.

Blockly CSS classes

Blockly uses CSS classes to provide the following kinds of information about the HTML and SVG elements it uses.

  • Type. Most Blockly CSS classes identify what an element represents. For example, the root element of a block is labeled blocklyBlock. Some elements are labeled with multiple classes, each more specific than the last. For example, the root element of a text input field is labeled blocklyField, blocklyInputField, and blocklyTextInputField. Type classes remain the same for the life of a component.

  • State. Blockly also uses CSS classes to specify the state of a component. For example, when the cursor is on a text input field, its root element is labeled with the blocklyEditing class. When the cursor is moved away, this class is removed.

  • Additional information. Blockly uses a few CSS classes to provide additional information. For example, the injection <div> has classes that provide the name of the workspace's current renderer and theme. These classes generally remain the same for the life of the application.

The easiest way to discover what CSS classes Blockly uses is to open your browser's developer tools and inspect the elements used by your application.

Custom CSS classes

You can use custom CSS classes to provide more specificity to Blockly components.

Workspaces

To add or remove a CSS class from a workspace's injection <div>, call WorkspaceSvg.addClass or WorkspaceSvg.removeClass.

Toolboxes

To add a CSS class to a button or a label in a toolbox, use the web-class key in your JSON definition of the toolbox. For more information, see Buttons and labels.

To override the CSS classes used for the various parts of a category, use the cssConfig key in your JSON definition of the category. This allows you to style individual categories. For more information, see Category CSS.

Blocks

To add CSS classes to a custom block, pass a string or array of strings to the classes key.

Blockly.common.defineBlocksWithJsonArray([{
  "type": "string_length",
  "message0": 'length of %1',
  "args0": [
    {
      "type": "input_value",
      "name": "VALUE",
      "check": "String",
    }
  ],
  "classes": "myStringLengthBlock",
  "output": "Number",
  "colour": 160,
}]);

You can also add or remove a CSS class from a block's <g> element by calling BlockSvg.addClass or BlockSvg.removeClass.

Label fields

To add or remove a CSS class from the <text> element used by a label field or serializable label field, call FieldLabel.setClass. You can also pass a class name to the label's constructor.

CSS classes and custom components

When constructing a custom component, use one of the following methods to add custom CSS classes:

  • If your component is a subclass of Field or Icon, override the initView method. For example:

    class MyCustomField extends Blockly.FieldTextInput {
      ...
    
      initView() {
        super.initView();
    
        // Add custom CSS class so we can style the field.
        if (this.fieldGroup_) {
          Blockly.utils.dom.addClass(this.fieldGroup_, 'myCustomField');
        }
      }
    }
    

    For more information, see Customizing fields with CSS or Create the icon's view.

  • When constructing an SVG element, pass your class to Blockly.utils.dom.createSvgElement:

    this.svgRoot = Blockly.utils.dom.createSvgElement(Svg.G, {'class': 'myCustomComponent'});
    
  • When constructing an HTML element, use Blockly.utils.dom.addClass:

    const myDiv = document.createElement('div');
    Blockly.utils.dom.addClass(myDiv, 'myInformation');
    

To add or remove classes after construction, use Blockly.utils.dom.addClass or Blockly.utils.dom.removeClass.

setMyHighlight(highlight) {
  if (highlight) {
    Blockly.utils.dom.addClass(this.svgRoot, 'myHighlight');
  } else {
    Blockly.utils.dom.removeClass(this.svgRoot, 'myHighlight');
  }
}

CSS rules background

If you understand SVG styling properties and the CSS cascade, you can skip this section.

SVG styling properties versus CSS properties

SVG elements are styled with SVG styling properties. These can be used as attributes on SVG elements (aka presentation attributes) or in CSS rules. Thus, all of the following do the same thing.

<!-- SVG file with presentation attributes. -->
<circle fill="red" ... />
<!-- SVG file with <style> tag. -->
<style>
  circle {fill:red;}
</style>
<circle ... />
/* External CSS file.*/
circle {fill:red;}
<!-- SVG file with inline style. -->
<circle style="fill:red;" ... />

The list of SVG styling properties is related to but different from the list of CSS properties:

  • Same concept, same name. For example, both SVG and CSS use direction to specify whether text is LTR or RTL.
  • Same concept, different name. For example, SVG uses fill to specify fill color; CSS uses background-color.
  • CSS only. CSS has many properties that are not in SVG, such as margin and padding.
  • SVG only. SVG has a few properties that are not in CSS, such as x and y.

Thus, if you're styling an SVG element, use SVG styling properties. If you're styling an HTML element, use CSS properties.

CSS cascade

The CSS cascade determines the priorities of CSS rules, which determine which rule to use if more than one rule applies to a given property and element. The following simplified cascade covers the parts of the cascade most commonly used by Blockly and may help you resolve the question, "Why doesn't my CSS work?"

Simplified cascade

To determine which rule applies to a particular element and property, follow these steps and stop when only one rule remains:

  1. Gather all the rules that apply to the property and element.
  2. If any rules have an !important annotation, discard all rules that don't have an !important annotation.
  3. Choose the rules with the highest specificity.

    • SVG presentation attributes have a specificity of zero.
    • Rules in a <style> tag or external stylesheet have their specificity calculated normally.
    • Inline styles (styles set by a style attribute) have a specificity higher than any selector.
  4. Choose the rule that appears last in the document.

  5. If no rule applies, inherit the property's value from the element's parent.

This algorithm does not consider the following parts of the cascade:

  • The transition property, which has the highest priority. Blockly uses a few of these.
  • The @media at-rule. Blockly uses one of these.
  • Rules specified by the browser or user.
  • The @scope and @layer at-rules and the animation property, which are not used by Blockly.

CSS rules

CSS rules specify how your application is styled. Blockly provides a default set of rules that you can override with your own rules.

Blockly CSS rules

Blockly provides a default set of CSS rules. How and where these rules are added affects their priority.

Style tags

The majority of Blockly's CSS rules are specified in two <style> tags. Because these tags occur near the top of the page, the rules in them have lower priority than rules with the same specificity that occur later in the page.

Blockly.css.register rules

When Blockly is injected, it adds a <style> tag as a child of the <head> tag. The rules in this tag come from:

  • The Blockly.css namespace. To see these rules, open core/css.ts and search for let content.
  • Individual components, which call Blockly.css.register to add component-specific CSS rules. Because css.register adds these rules to the end of the content string, they have higher priority than rules with the same specificity that were added earlier. To see these rules, see the calls to Blockly.css.register.

If you do not want to use these rules, set the css configuration option to false. In this case, you are responsible for providing an alternate set of CSS rules.

Renderer rules

When the renderer is instantiated, it adds a <style> tag containing renderer-specific CSS rules as a child of the <head> tag. Note that these rules are always added -- they are not affected by the css configuration option. To see these rules, search for the getCss_ method in your renderer.

Inline styles

Inline styles are specified with the style attribute and are generally created when the DOM for a component is created. For a partial list, see this GitHub query.

Inline styles apply directly to the element on which they occur and have a specificity higher than any selector. For this reason, overriding them generally requires you to use an !important annotation.

SVG presentation attributes

SVG presentation attributes are SVG styling properties used as attributes of SVG elements. They have a specificity of zero and cannot contain an !important annotation, so they have the lowest priority of all of Blockly's rules. Blockly generally creates them in calls to createSvgElement.

Add your own CSS rules

You can add your own CSS rules using the same methods as Blockly:

  • Call Blockly.css.register before injecting Blockly. Your rules will be added after Blockly's and have a higher priority than Blockly rules with the same specificity.
  • Add a <style> tag or link to an external style sheet as a later child of the <head> tag. Because Blockly adds its rules as the first two children of the <head> tag, your rules will have a higher priority than Blockly rules with the same specificity.
  • Use inline styles to add styles to elements in a custom component. These rules will have a higher specificity than any rules with a selector.
  • Use presentation attributes on SVG elements in a custom component. These rules will have a lower specificity than any rules with a selector.

Troubleshooting

If your CSS is not working, here are some possible causes:

  • You are using CSS properties on an SVG element or SVG styling properties on an HTML element. See SVG styling properties versus CSS properties.

  • Your rule has a lower priority than another rule. This is usually due to a lower specificity. Possible ways to fix this are:

    • Use a class selector instead of a type (element) selector.
    • Use multiple selectors.
    • If possible, add a custom class to your target element and use this class in your rule.
    • As a last resort, add an !important annotation to your rule. This is your only choice if a competing rule is specified using an inline style (style attribute).
  • Your rule has the same specificity as another rule, but occurs earlier in the page. If you cannot increase the specificity of your rule, move it later in the page.

There are two types of CSS rules you cannot override:

  • Properties that are set inside a transition rule.
  • !important rules specified by the browser.