mirror of
https://github.com/penpot/penpot.git
synced 2026-10-30 14:30:37 +00:00
🐛 Render no type attribute on DS buttons used as links (#12709)
* 🐛 Render no type attribute on DS buttons used as links With `to`, button* renders an <a href> but still passed type="button". On an anchor, type is a MIME type hint, so "button" is invalid HTML. The type now applies only when the element is a <button> (still "button" by default). New "As Link" story with two tests: the link has its href and no type, and a plain button keeps type="button". AI-assisted-by: claude-opus-5-5 * 📚 Document the DS button as a link The Semantics section only said that button* accepts `to`. It now says when to use it (the control goes to another URL), what it renders (an <a href> with the button style and no type), how to keep the in-app navigation on a plain click, and shows the "As Link" story. AI-assisted-by: claude-opus-5-5
This commit is contained in:
parent
12dd4d19d0
commit
0fa1077b9a
@ -36,7 +36,8 @@
|
||||
:button-destructive (= variant "destructive"))
|
||||
props (mf/spread-props props {:class [class internal-class]
|
||||
:href to
|
||||
:type (d/nilv type "button")
|
||||
;; On an anchor, `type` is a MIME type hint.
|
||||
:type (when-not to (d/nilv type "button"))
|
||||
:ref (fn [node]
|
||||
(when on-ref
|
||||
(on-ref node)))})]
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
|
||||
import * as React from "react";
|
||||
import Components from "@target/components";
|
||||
import { within, expect } from "storybook/test";
|
||||
|
||||
const { Button } = Components;
|
||||
const { icons } = Components.meta;
|
||||
@ -67,3 +68,34 @@ export const Destructive = {
|
||||
variant: "destructive",
|
||||
},
|
||||
};
|
||||
|
||||
// With `to`, the button renders an anchor: it keeps the button look but it is
|
||||
// a real link (href, open in a new tab, announced as a link).
|
||||
export const AsLink = {
|
||||
args: {
|
||||
variant: "secondary",
|
||||
to: "https://penpot.app",
|
||||
children: "Go to Penpot",
|
||||
},
|
||||
};
|
||||
|
||||
export const TestAsLinkRendersAnchor = {
|
||||
args: AsLink.args,
|
||||
play: async ({ canvasElement }) => {
|
||||
const link = within(canvasElement).getByRole("link", {
|
||||
name: "Go to Penpot",
|
||||
});
|
||||
await expect(link).toHaveAttribute("href", "https://penpot.app");
|
||||
// `type` on an anchor is a MIME type hint, not a button type.
|
||||
await expect(link).not.toHaveAttribute("type");
|
||||
},
|
||||
};
|
||||
|
||||
export const TestButtonDefaultsToTypeButton = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const button = within(canvasElement).getByRole("button", {
|
||||
name: "Lorem ipsum",
|
||||
});
|
||||
await expect(button).toHaveAttribute("type", "button");
|
||||
},
|
||||
};
|
||||
|
||||
@ -71,8 +71,23 @@ Action buttons are a variant of `icon-button*` (`"action"`) but smaller.
|
||||
|
||||
### Semantics
|
||||
|
||||
In some cases, a button needs to be semantically an 'a' tag, but visually maintain the button style.
|
||||
In that case, the button accepts a 'to' property with the expected 'href'. It will then be rendered as an anchor element.
|
||||
When the control takes the user to another page or URL, it must be a link, even if it looks like a button.
|
||||
Pass the destination in `to`: `button*` then renders an `<a href>` with the button style, so it can be
|
||||
opened in a new tab and assistive technologies announce it as a link. It renders no `type` attribute,
|
||||
which on an anchor would mean a MIME type.
|
||||
|
||||
```clj
|
||||
[:> button* {:variant "secondary"
|
||||
:to (rt/resolve-uri router :auth-login {})}
|
||||
(tr "profile.recovery.go-to-login")]
|
||||
```
|
||||
|
||||
To keep the in-app navigation on a plain click, add an `on-click` that calls `prevent-default` (unless
|
||||
Ctrl/Cmd is pressed) and emits the navigation event. Other anchor attributes, such as `target`, pass through.
|
||||
|
||||
<Canvas of={ButtonStories.AsLink} />
|
||||
|
||||
Use a plain `button*` (without `to`) for actions that do not change the URL, such as opening a modal.
|
||||
|
||||
### Accessibility
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user