Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Discussion options

Hi,

I have a container widget and via certain user interactions on other widgets this container gets children added or removed.

Whenever there are no regular children in the container, like the first time it's mounted or whenever the last regular child is removed, I'd like to show a similar looking placeholder child instead.

My issue is that I can't figure out how to know when that's the case, at least not in a way that I'd consider more or less idiomatic.

I've looked at the code side but there doesn't seem to be a built-in way to let the container know when children are mounted or unmounted.

I've also looked at the CSS side but unfortunately there doesn't seem to be a :not pseudo-class which I could use to hide the placeholder when it's not the first and last child.

So, the only way I can currently think of is to keep state in a reactive and toggle the placeholder that way, but it seems a bit much overhead considering I don't really need this state for anything else.

Any ideas are much appreciated 🙏

You must be logged in to vote

Replies: 1 comment · 1 reply

Comment options

The pseudo-class you're after is :empty, not :only-child. It matches a widget that has no displayed children, so it's exactly the "is this container empty right now" hook you were looking for on the CSS side. It updates live as children mount and unmount.

The catch: Textual only has the descendant (space) and child (>) combinators. No sibling combinators (+, ~), so you can't write #items:empty ~ #placeholder to flip a separate placeholder widget from pure CSS. That's the wall you hit.

Two ways around it, neither of which needs the extra reactive.

If the placeholder can just be the empty container dressed up, style the container and give it a border title:

def compose(self) -> ComposeResult:
    items = Container(id="items")
    items.border_title = "Nothing here yet"
    yield items
#items:empty {
    border: round $panel;
    align: center middle;
}

border_title renders whether or not the container has children, so it shows through when empty and just gets covered once you mount real children.

If you want a distinct placeholder widget, don't fight CSS for it. Toggle it in the same place you already add and remove children:

self.query_one("#placeholder").display = not self.query_one("#items").children

One line, at a point you're already touching, no separate state to keep in sync.

You must be logged in to vote
1 reply
@dAnjou
Comment options

The pseudo-class you're after is :empty, not :only-child.

Sorry, I forgot to update the link title (see edit history), I was linking to the :not pseudo-class, which is also what I meant originally.

If the placeholder can just be the empty container dressed up, style the container and give it a border title:

I think I'd rather stick with the distinct placeholder widget, matter of taste, I know, but I like it better.

Toggle it in the same place you already add and remove children [...] One line, at a point you're already touching, no separate state to keep in sync.

Adding and removing children is not exactly happening in the same place because it's triggered from within different widgets.


It's okay though, the extra reactives came in handy in other ways now, so it's not too bad. A :not pseudo-class would make it a tad more elegant though 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
🙏
Q&A
Labels
None yet
2 participants
Morty Proxy This is a proxified and sanitized view of the page, visit original site.