Skip to content

feat: implement flexible pseudo element and pseudo class input#5546

Closed
zehjotkah wants to merge 5 commits intowebstudio-is:mainfrom
zehjotkah:feat/pseudo-elements-and-pseudo-classes-support
Closed

feat: implement flexible pseudo element and pseudo class input#5546
zehjotkah wants to merge 5 commits intowebstudio-is:mainfrom
zehjotkah:feat/pseudo-elements-and-pseudo-classes-support

Conversation

@zehjotkah
Copy link
Contributor

This PR replaces the limited "States" dropdown in the Style Panel with a flexible input field that supports any CSS selector, pseudo-class, or pseudo-element. This allows for advanced styling capabilities such as :has(), :focus-visible, and complex combinators.

Key Changes

Flexible Selector Input

  • Replaced the fixed "States" category list with a free-form input field.
  • Supports any valid CSS selector (e.g., :hover, ::before, :has(:checked)).
  • Validation logic ensures only valid selectors are accepted (triggered on Enter key).

How to Test

  1. Select an element and open the Style Panel.
  2. Click on the Local style source or a Token.
  3. In the input field (bottom of menu), type a selector like :hover or :first-child and press Enter.
  4. Verify the selector is added and selected.

@TrySound
Copy link
Contributor

TrySound commented Dec 29, 2025

This can work for pseudo classes though there is a problem with pseudo elements which are actually children of selector they use. This means our style engine will compute values by cascade rather than inheritance.

See for example

MyToken {
  width: 10px;
  color: red;
}
MyToken::before {
  height: 20px;
}

Having pseudo element as state will compute as

width: 10px;
color: red;
height: 20px;

While in reality "before" would not have width inherited.

The way it is rendered via parent class is already solved by descendant component. Only need to duplicate its logic for pseudo elements.

@zehjotkah
Copy link
Contributor Author

zehjotkah commented Dec 29, 2025

not 100% sure if I understand it correctly.
Check the screenshot. "Hello Oleg" is the pseudo element ::before with background: red.
It's attached to a token which was added to both div element 1 and 2

Bildschirmfoto 2025-12-29 um 14 27 56

edit: okay, maybe I understand it. Will try to fix it. But I don't think that we should display pseudo elements in the html tree.

@zehjotkah
Copy link
Contributor Author

zehjotkah commented Dec 29, 2025

@TrySound do you want pseudo elements being added only via the HTML tree and being attached only to HTML elements?

I think a very useful feature of pseudo elements is to be attached to CSS classes/tokens.
For example on nearly every website I use a clickable-parent and stretched-link utility class.

.clickable-parent {
    position: relative;
    cursor: pointer;
    display: block;
  }

  .clickable-parent:focus-visible,
  .clickable-parent:has(:focus-visible) {
    outline: var(--focus-width) solid var(--focus-color);
    outline-offset: var(--focus-offset);
  }

  .clickable-parent:focus-within :focus {
    outline: none;
    box-shadow: none;
  }

  .stretched-link {
    text-decoration: none;
    color: inherit;
  }

  .stretched-link::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 1;
  }

If I can only add a pseudo element via the HTML tree I couldn't do the above.

Or do you mean that we should add the pseudo element via the token but display it also in the HTML tree?
Wouldn't then the user be confused where to style the pseudo class?

@kof
Copy link
Member

kof commented Dec 29, 2025

Its also about how psuedo element is:

  1. getting added
  2. getting reused
  3. getting deleted

So I agree token interface is a good fit, but you also need to solve:

  1. once selected from token menu - selected instance must change, you are no longer on the parent instance
  2. style panel computation should be then automatically correct

You need both, tree and token menu. Tree node must be ephemeral, only created when pseudo element is selected from the menu.

@TrySound
Copy link
Contributor

Here's better example to clarify what I have in mind. Non technical user may not understand details content is defined in css and can be accessed with state.

image

Pseudo-elements (like `::before`, `::after`, `::placeholder`) were incorrectly **cascading** properties from their parent element instead of **inheriting** them according to CSS specifications. This meant non-inherited properties like `width`, `height`, and `display` were incorrectly appearing on pseudo-elements.
@iocouto
Copy link

iocouto commented Dec 29, 2025

Just my 2 cents: pseudo-elements are elements that can have their own styles, states and scripts attached to them — they are not a 'style'. Elements in Webstudio are displayed in the Navigator, and that is the most intuitive place to have them. The Style Editor - including tokens - are for managing CSS styles. It would be much more helpful for newbies to keep that distinction.

@zehjotkah
Copy link
Contributor Author

zehjotkah commented Dec 29, 2025

@iocouto thanks for your input!

You could also argue that in Webstudio HTML is "written" in the elements panel and CSS is "written" in the styles panel.
-> pseudo elements are written in CSS but they behave a little bit like HTML.

Also pseudo elements are not actual nodes in the DOM. Because they don't exist in the DOM tree, you cannot assign them attributes like an ID.
With JavaScript you'd need to target its parent element (which is in the DOM).

How would be the best way for you to attach a pseudo element to a CSS token in Webstudio?

@iocouto
Copy link

iocouto commented Dec 30, 2025

@zehjotkah I totally understand where you're coming from, but it's important for us to remember that when you say that "HTML is written in X, while CSS is written in Y", you're viewing your website building from the perspective of a PROGRAMMER: someone who already knows HTML & CSS, and who understands how HTML/CSS and pseudo-elements work. That is not necessarily the primary target audience of Webstudio: as you can see from the questions and support enquiries in the Discord server, there will be many, many users who are new to Web Development, and who view Webstudio as a way to 'design a website' rather than 'program a website'.

Newbie Web Designers are not likely to be familiar with how we define pseudo-elements in CSS, and are unlikely to intuitively view pseudo-elements (such as 'placeholder') as part of a "style" definition. Intuitively, they will likely see them as separate elements in their own right, which they should be able to select in the Navigator and 'style' in the same way as other elements — eg., the same way they can select 'options' inside 'select' elements, or even 'bold' or 'span' elements inside a 'p'...

@kof
Copy link
Member

kof commented Dec 30, 2025

I agree with @zehjotkah , the north star here is not what a newbe might think ( most newbies might never need to make use of it in the first place), its "who is the owner of that code" and who is "managing that code", pseudo element is owned by css, so its logical they should be found over style panel.

Delete a token - pseudo element must be gone
Copy a token (coming) - pseudo element must come with it
Add a token to an instance - same.

All these manipulations would be completely impossible without attaching pseudo element to the style source, where it physically lives in the actual real world CSS.

Our north star has always been to never hide how things actually work.

@kof
Copy link
Member

kof commented Jan 18, 2026

TBC in #5572

@kof kof closed this Jan 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants