Colon in Class Names

I’m about to break my own rules again.

Table of Contents
  1. Core Concept
  2. The Future of Panel
  3. Changes to Layout Class Names

Core Concept

The current page conditional statement feature uses state data to allow CSS and JavaScript authors to use the generated HTML class names to make certain rules specific to a condition without having to mix their code with PHP rules in it. The feature is very simple. It uses a key such as is and not as a base condition, following the actual rule name to hold the rule state, with its value to be checked later in an if condition in the layout:

<?php

// In your extension file…
Site::set('is.post', str_starts_with($url->path . '/', '/article/'));
<!-- In your layout file… -->
<?php if ($site->is('post')): ?>
  <h2>
    <?= i('Post'); ?>
  </h2>
<?php else: ?>
  <h2>
    <?= i('Page'); ?>
  </h2>
<?php endif; ?>

This feature, despite being so simple, is actually open to unlimited conditional statement rules that anyone can make and tweak as they like, without my intervention. In the future, someone may want to dedicate her/him self to develop an all-in-one extension specifically to provide rules for page conditional statements.

The Layout extension will capture all states stored in the are, as, can, has, is, not, of, and with keys to generate HTML class names. It uses a colon to separate the base condition and its rule name, which is cool, as if it were a real rule in a programming language that can do something despite being just an HTML class name that makes the element status more specific. It is so cool that even the Panel extension uses the key:key format as its class name all over the place!

<html class="is:post"> … </html>

Later, CSS and JavaScript authors can write their rules based on that specific conditions without having to mix their code with PHP rules:

.is\:post h2 {
  color: #f00;
}
if (document.documentElement.classList.contains('is:post')) {
    document.querySelectorAll('h2').forEach(h2 => (h2.style.color = '#f00'));
}

The Future of Panel

As the author of the Panel extension, I know that developing sub-extensions for Panel is quite tedious. You have to use an array to construct the control panel layout, which requires extra time to learn the specification, just to generate the HTML string that you are probably more familiar with and comfortable writing its syntax by hand.

Learning from the previous mistake, and in the spirit of “not introducing new syntax into the application data”, I propose an HTML custom element feature to allow control panel extension authors to develop control panel layout using native HTML syntax if they wish, without having to discard the old way of constructing HTML syntax using array. Once the feature is available, the old way of constructing HTML syntax using array will return an HTML string with their custom names instead of returning an HTML string with custom class names:

<html class="has:part has:user is:panel">
  <head>
    …
  </head>
  <body>
    …
    <panel type="files">
      <panel:bar is:flex>
        …
      </panel:bar>
      <panel:desk>
        <panel:form action="/get/asset/1" method="post" name="set">
          <panel:section>
            <panel:tasks type="buttons">
              <panel:task icon="…" kick="/set/asset?type=blob" title="" type="button"></panel:task>
              <panel:task icon="…" kick="/set/asset?type=file" title="File" type="button"></panel:task>
              <panel:task icon="…" kick="/set/asset?type=folder" title="Folder" type="button"></panel:task>
            </panel:tasks>
          </panel:section>
          <panel:section>
            <panel:tabs current="files" name="0">
              <panel:tab name="files" title="Files">
                <panel:files chunk="20" part="1" path="<?= LOT . D . 'asset'; ?>"></panel:files>
                <panel:pager chunk="20" count="<?= q(g(LOT . D . 'asset')); ?>" part="1"></panel:pager>
              </panel:tab>
              <panel:tab name="…">
                …
              </panel:tab>
              <panel:tab name="…">
                …
              </panel:tab>
              …
            </panel:tabs>
          </panel:section>
        </panel:form>
      </panel:desk>
    </panel>
    …
  </body>
</html>

There’s a problem: The HTML specification does not allow the : character in a name, and a name must contain at least one - character to avoid conflicts with new native HTML element names in the future.

From the example above, you can see that <panel> and <panel:*> are not valid custom HTML elements, and therefore cannot be made. I haven’t confirmed this, but it looks like the rules apply to attributes as well (except for the - character requirement), so it’s best to stick to the kebab-case naming style, I think:

<html class="has-part has-user is-panel">
  <head>
    …
  </head>
  <body>
    …
    <panel-layout type="files">
      <panel-bar flex>
        …
      </panel-bar>
      <panel-desk>
        <panel-form action="/get/asset/1" method="post" name="set">
          <panel-section>
            <panel-tasks type="buttons">
              <panel-task icon="…" kick="/set/asset?type=blob" title="" type="button"></panel-task>
              <panel-task icon="…" kick="/set/asset?type=file" title="File" type="button"></panel-task>
              <panel-task icon="…" kick="/set/asset?type=folder" title="Folder" type="button"></panel-task>
            </panel-tasks>
          </panel-section>
          <panel-section>
            <panel-tabs current="files" name="0">
              <panel-tab name="files" title="Files">
                <panel-files chunk="20" part="1" path="<?= LOT . D . 'asset'; ?>"></panel-files>
                <panel-pager chunk="20" count="<?= q(g(LOT . D . 'asset')); ?>" part="1"></panel-pager>
              </panel-tab>
              <panel-tab name="…">
                …
              </panel-tab>
              <panel-tab name="…">
                …
              </panel-tab>
              …
            </panel-tabs>
          </panel-section>
        </panel-form>
      </panel-desk>
    </panel-layout>
    …
  </body>
</html>

Changes to Layout Class Names

To keep the entire ecosystem consistent, I may change my standard in a few days to replace those colon-separated class names with dash-separated class names.

Most of the layouts I have built currently do not fully utilize the class names in the CSS and JavaScript code, but if you have used them in some of your code, it is better to include the dash-separated class names in your selectors from now on, for backward compatibility:

.is-post h2,
.is\:post h2 {
  color: #f00;
}
if (document.documentElement.matches('.is-post, .is\\:post')) {
    document.querySelectorAll('h2').forEach(h2 => (h2.style.color = '#f00'));
}

See you in the future! 👋

0 Comments

No comments yet.