Admin UI: Add icon prop to Page header component#76469
Admin UI: Add icon prop to Page header component#76469CGastrell wants to merge 10 commits intoWordPress:trunkfrom
Conversation
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
|
Thinking if |
afba908 to
09361c5
Compare
|
FYI I updated PR title+description to use |
1f04fb7 to
6a17159
Compare
|
Have you considered rendering an What I'm worried about is that we're introducing an abstraction that may not be flexible enough for future needs. I'm also lacking the overall vision for Page and admin UI — rather than adding a little piece at a time and risk building the wrong abstractions, I think it would be better to take a step back, understand all the requirements, and figure out the best abstractions / implementations to satisfy them (cc @WordPress/gutenberg-components ) |
|
Yes, seeing the Warning signs: There are three props on root-level |
|
@mirka context for the recent ariaLabel and headingLevel additions:
Both are related to accessibility, but the flexibility of h1-h6 heading option seems kinda lot to me. I don't know enough about use-cases if heading ever needs to be anything else than h1; maybe? |
As far as I can tell, the structure of admin-ui's Page is to provide a consistent look throughout pages that will live on the site admin. This is where we're coming from, the multiplicity of pages and styles built on wp-admin. Now, we want to be flexible, but we also want to set some sort of "standard". In that regard I don't see many abstractions, hence why Header is not (yet) exposed, it only exists through Page props. And it aims to always look the same. Title, Breadcrumbs and Badges are all Page props that then get passed down (internally) to Header. If we want to add full flexibility, then this shouldn't happen and we'd need to expose/export Header, allowing consumers to: <Page>
<Header />
<SomeOther />
</Page>But that would still suffer the same consequences: consumer would need to compose Header in the same way it would need to compose Page. Right now Header is the one sorting out how/when things are rendered and, in some cases, it even delegates or expects props to provide the right components (Breadcrumbs needs to be passed down, it's not constructed from an array). So, with this same approach, the proposed Is this a constraint we want? I assumed yes. Otherwise the consumer can use its own component for the page they need. Page, from my PoV, exists to provide a unified way to build pages to integrate seamlessly into the admin. Whatever magic we put in there is only meant to keep design aligned, that means restrictions, yes, but also the benefit of having things work out of the box. Now, back to the Shall a consumer want to fully customize its page they can, if Page doesn't receive any of the three props (title, breadcrumbs or badges, and now icon) the Header is not rendered and the consumer can enjoy a fully blank canvas to work on. This is the "off-road" option we can offer, but once a single of those props is provided, we want it to be consistent and Page uses Header to render it, keeping the flexbox behavior and alignment in this unified way. That said, we might also be more worried about @mirka @ciampo I see the concern, and I agree this might be a completely different discussion on structural design of the component. I'm just saying that this decision will affect the current way we expose/render the Header and, once we come to that decision, it should be the same work to migrate any of those props as it would be to migrate |
Not questioning the necessity of the prop, but the naming (or API structure) here. A plain root-level Not just the unclarity, but it's problematic when you eventually need to accept custom aria-labels on other internal elements that are also covered by root-level props. How exhaustive are the props we have now (genuine question because I don't know)? There are root-level props applying to the There's a balance to be found between ergonomics, consistency, and modularity, but we've found it easier to find that balance by starting from the fully modular, then at the end tweaking ergonomics and consistency in the monolithic component. Maybe that is what is happening here, because the code does show internal modularity, but the way props are all flatly exposed on the monolithic component gives me pause, if we're not close to exhausting our prop set yet. And there are type-friendly, ergonomic ways to mitigate root-level prop bloat, for example |
Completely agree from a component design PoV. Though, this would be a breaking change, not for the sake of blocking it, just to make sure we take the necessary precautions before such change. On top of it, I like the Out of the scope of this PR but, anyone up to prepare such change? |
6a17159 to
242ded6
Compare
|
BTW, fixing the actions bug: #76695 |
|
Outside of the excellent discussion so far I'd like to point out that the dimensions of the #76709 suggests 20x20, but that won't play nicely with |
242ded6 to
633e2a1
Compare
54bd9fb to
f1fcfc5
Compare
|
Looking at the spec (#76709) it seems icons and images are to be treated the same way, so |
Just to confirm, the prop should be renamed from <Page title="Page title" visual={ <Icon icon={ wordpress } size={ 24 } /> }>...</Page> |
|
That makes more sense to me, given it can render things that are not icons. |
f1fcfc5 to
42f87a2
Compare
|
@jameskoster I pushed the rename from |
| title: 'Page title', | ||
| visual: ( | ||
| <img | ||
| src="https://s.w.org/about/images/logos/wordpress-logo-notext-rgb.png" |
There was a problem hiding this comment.
Tiny detail, but this kind of looks like an icon when rendered, while the story is supposed to demonstrate using an image. Is there an alternative placeholder we could use? Matt's gravatar or something?
42f87a2 to
0a7c313
Compare
|
I switched the sample image for Matt's gravatar. Then addressed the other comments, they all made sense to me. |
|
Seems good from a design perspective 👍 |
|
Let's include a changelog entry for admin-ui. |
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace custom GlobeLogo SVG with the WordPress icon from @wordpress/icons and remove the image-based logo story that didn't render well. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rename the Page header logo prop to icon for consistency. Remove the JetpackLogo component and its stories as brand logos don't belong in the component library. Rename CSS class accordingly. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
0a7c313 to
925cd17
Compare
Added on 925cd17 Thanks for pointing it out! |
ciampo
left a comment
There was a problem hiding this comment.
Although I'd like to rethink the whole Page abstraction holistically, adding the visual prop can work as a short-term addition to unlock consumption of the component
| img, | ||
| svg { |
There was a problem hiding this comment.
Any reason in particular why we're targeting img and svg elements? What if a different tag (eg figure, video, etc) is passed?
These styles may be unnecessary and introduce a wrong abstraction and/or a style leak: IMO, it's the consumer who's passing visual who should ensure the visual element that is being passed is styled correctly.
If we want to control the layout a bit more intentionally, we could potentially use CSS grid? ie. a 1x1 grid, forcing all children to occupy the grid cell;
.admin-ui-page__header-visual {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr;
width: 24px;
height: 24px;
> * {
grid-column: 1 / -1;
grid-row: 1 / -1;
}
}
See design convo #76709
What?
Adds a
iconprop to the Page component's header, allowing consumers to display a logo or symbol alongside the title or breadcrumbs.See #76448
Why?
As described in #76448, consumers currently pass logos inside the
titleprop, which places them inside theh2tag. This is fragile and creates accessibility issues — when the title contains non-text content, a separateariaLabelmust be passed to maintain good semantics (see #75898).An officially supported
iconprop renders the logo outside theh2tag, ensuring:ariaLabelif the only difference is the icon betweentitleandariaLabel.How?
icon?: React.ReactNodeprop toPage(index.tsx) andHeader(header.tsx)div.admin-ui-page__header-logoobject-fit: containfor img/svg childrenTesting Instructions
npm run storybook:devWith Logo: globe icon + "Page title" headingWith Jetpack Logo: Jetpack icon + "Jetpack" headingWith Logo And Breadcrumbs: globe icon + breadcrumb navigationWith Jetpack Logo And Breadcrumbs: Jetpack icon + breadcrumb navigationh2elementTesting Instructions for Keyboard
EOF
)