Talend / ui

Talend's unified web UI repository.
http://talend.surge.sh
Apache License 2.0
151 stars 54 forks source link

[RFC]: Button as Link or Link as Button, and vice-versa? #3850

Closed frassinier closed 1 year ago

frassinier commented 2 years ago

Context

We need to display links rendered as buttons and the opposite, for semantic reasons, with minimal effort.

Problems

We used to deal with <Button as={Link} href /> and now they are renamed to <ButtonAsLink href /> in the fresh last new version of the Design System.

buttonAsLink

And we have the same behavior for the Links.

linkAsButton

This naming seems a little bit hard to guess for some of us.

Solutions

We need your feedback on that point. Should we use a better naming? Otherwise, put a simple emoji here so we can keep that naming because... it's ok, and we can move forward.

jsomsanith-tlnd commented 2 years ago

I think the current names are clear as we read them exactly the same way as the as props. In your example: <Button as={Link} /> is read Button as Link === <ButtonAsLink /> is read Button as Link (mic drop + kiss)

pgu commented 2 years ago

Hello,

Disclaimer: My experience is...

Now, I'm trying to get the whole picture to understand why the current naming proposal and here is my understanding of the current topic: For better developing and maintainability experience, there is a need to have 2 distinct types between "button" and "link" in order to enforce their attribute API:

Also, we need:

Also, I'd add this constraint: When I set a href to a component, I'd expect it to generate an anchor tag <a/>. (see my HTML bias here...)

Last point: those components are at the lowest levels: molecules (ie very close to HTML... you see me coming ;)

So, this is what I have in mind. And I don't know about other need or constraint that should be included (this is why the RFC is here, to get the whole context of the topic).

So, here is my current thinking:

My current "mental model" is: 1) want to set a path /the/path? => go for an href: write <a href="/the/path" /> 2) want to look like a primary action? add class name btn-primary.

That's it. Another scenario: I need to change the link for a button because there isn't any navigation involved anymore: 1) Let's find the link 2) change the <a/> tag to <button/> tag 3) update attributes and values accordingly.

So, I'd expect a similar experience with the proposed types: 1) want to set an href? write <Link href="/" /> 2) want to look like a primary action? add attribute styledAs="PRIMARY" (for example)

And that's it: I know <Link/> will generate an anchor tag, so I know that the HTML output is as expected, and so, with all its native characteristics (the browser navigation will work as expected, etc). Also I already guess most of the attributes <Link /> will offer me or not.

And the same for <Button />, I expect it to have an API close to the <button> HTML and to output a <button> and handles all its states.

=> The mapping is straightforward, no surprise in the api, no surprise in the behaviour, and the api is enforced for each type. (==> why would we need to have another mapping? creating unexpected output? unexpected behaviour? creating more confusion?)

From there, I don't expect another molecule component to offer me the href attribute. And I think this is aligned with the primary need to have 2 distinct types. Also, as seen, the styling requirement is answered with an attribute styledAs (or another explicit naming? for example: as isn't explicit enough: has it an effect on the DOM ouput? is it about style only? what will be the resulting html tag? and even, why should we use this attribute at all? if there is an href, shouldn't it generate a <a/> automatically? if yes, why the element is called Button if it won't generate <button> but <a>? why not a more generic term like Action? but then, how do you enforce distinct API attributes between one case and another? Right now, I can't wrap my head around this strategy).

So, to sum up: just with <Button> and <Link> mapped 1:1 to <button> and <a>, and an attribute for style, looks like it covers criteria listed above.

But, I think I miss some other criteria, what are they?

Maybe there is a doc about all criteria that need to be taken into account for this topic? If you could provide a link, styled as a link ;), would be helpful.

(sorry for stating whatever could appear as being obvious above)

cc @frassinier @Benrajalu

sgendre commented 2 years ago

Element nature should have priority over element UI, so it should be

<LinkAsButton href>
<LinkAsButtonPrimay href>
<LinkAsButtonSecondary href>

and so on...

pgu commented 2 years ago

But still, ButtonAsLink/LinkAsButton? We are at the "atom" level; we know HTML API and we are very close to it. Why a mapping 1:1 between <Button>/<button> and <Link>/<a> with a separation of concern for managing style, isn't enough?

Isn't it a convulted way to produce an anchor tag by using ButtonAsLink? instead of just <Link> or change a <a/> to a <button/> with <LinkAsButton>? instead of just replacing <Link> by <Button>? (combination such as <Link styledAs="PRIMARY">, <Button styledAs="LINK">, ... isn't enough?)

Why do we need them? By extension, should I expect? <GridAsTable/> - <TableAsGrid/> <InputAsSelect/> - <SelectAsInput/> (ex: UIselect, an advanced "select" box, is implemented with an input and divs) (<InputAsTextarea/> ...)

There must be some information I'm missing to understand why at this level (atom), there are these components.

Benrajalu commented 2 years ago

@pgu

Some answers to your questions:

pgu commented 2 years ago

Ok, thanks @Benrajalu for the pointers and the requirements I was missing.

pgu commented 2 years ago

OK, about the as, I can see, this is something like: <Link as="div" ... /> <Button as="div" ... /> (sorry to hurt your eyes ;) from Reakit though >< ) => there is a hierarchy of information: This component (Link or Button) will still look like and behave like it's supposed to, but the HTML tag will be div => no confusion about the as effect.

Now to put this "detail" at the same level of the component name breaks this hierarchy, and, create some confusion, especially with the following fact:

Aren't there other available naming strategies? ex: 1)

(1) as_ + name of the HTML tag (2) avoid same case as existing component, such as Button => it reduces the confusion, and may be closer to the intention of the message we want to convey.

Note: link is intentionally discarded to avoid even more the association to the component Link.

2) LinkWithDOMButton ButtonWithDOMAnchor ?

3) any other ideas?

One of this strategy above would create less confusion and still help with all requirements, no?

Benrajalu commented 2 years ago

By the way, ButtonPrimaryAsLink then becomes a Linkable, and LinkAsButton becomes a Clickable.

(ButtonAsLink is just a facade, the actual components are standalone variants)

<Link as={<ReactRouterLink to="pouet" />} data-testId="link-pouet">Pouet</Link>

// is as valid as

<ButtonPrimaryAsLink as={<ReactRouterLink to="pouet" />} data-testId="link-pouet">Pouet</ButtonPrimaryAsLink>

// but crucially: they are not necessarily HTML anchors, because the "as" prop decides what they are

Maybe you'd then rather have <LinkableButtonPrimary> and <ClickableLink> (😬 )?

https://github.com/Talend/ui/blob/master/packages/design-system/src/components/Clickable/Clickable.tsx

https://github.com/Talend/ui/blob/master/packages/design-system/src/components/Linkable/Linkable.tsx

pgu commented 2 years ago

After a chat with Benoit, it helps understanding that actually, there is a pre-requisite when talking about Design System topics. This pre-requisite is that DS falls within another paradigm of DX.

As mentioned before, my current paradigm of DX is: ("functional" before "style") (0) I need to set an action to go to '/the/path/' (1 - functional) Navigation to a path? then go for an anchor tag <a/> and set its href (2 - style) Then, style it, ie add a classname (primary, secondary, whatever).

And here is the crux of the current discussion: DS is the other way around: ("style" before "functional") (0) I need to set an action to go to '/the/path/' (1 - style) Check with UX persona to see where this action should be placed, etc UX persona can then decide what it should look like. (2 - style) UX personas will express themselves with the UI PoV, (defined in Figma and documented in DS), ex:

"In this page, you'll need to present it as a secondary button."

=> As a frontend developer, I'm aware of their UI PoV, so, "button" actually means an action looking like a button. (3 - functional) As a frontend developer, I know the DOM result should be an anchor. So, my search needs to start with the UI PoV of UX Persona (SecondaryButton), and then, look for the element from my PoV (Link) in the DS lib (link).

Even if I'm not used to it, I can appreciate the fact that:

So, with this pre-requisite in mind, the naming is actually following this DX paradigm. First, what it looks like. Then, the "As" part is about how it should be generated and its impact is never on the UI level.

Component name Component UI result Component DOM tag & API
Link anchor UI anchor tag & anchor-like API
LinkAsButton anchor UI button tag & button-like API
Button button UI button tag & button-like API
ButtonAsLink button UI anchor tag + anchor-like API
Note: An idea to make the prerequisite more "explicit" would be to express it through the naming, ex: UILink, UIButton, ... And we would have for example: Current New
Link UILinkAsLink
LinkAsButton UILinkAsButton
Button UIButtonAsButton
ButtonAsLink UIButtonAsLink

And here, there isn't a misunderstanding about what we're talking about:

But, all DS components would end up with UI prefix, cluttering the whole lib component names. So, as it concerns few components and now that the expected DX is explained, then there isn't a strong need for it.

So, as a conclusion, with this pre-requisite in mind, it's all good from my side. Thx, bye.