Development notes
Looking like a button does not mean it should be a <button>
How this site uses product links, article contents, and drawer controls to share a visual style while keeping navigation, actions, and form submission distinct in HTML and browser behavior.
- HTML
- Interface semantics
- Astro
- Component design
“View product” and “Open contents” can share the same rounded corners, border, and hover effect, yet do different things when clicked. One takes the reader to other content; the other changes the interface state on the current page.
If both render as <button> just because they look like buttons, navigation can easily become a click script. Conversely, writing every control as <a href="#"> turns links into substitutes for actions that have no destination.
This site uses a shared Button component, but I first identify the operation, then choose the HTML it should render. The component name describes its appearance. It should not decide the semantics of every place where it is used.
Give navigation a real destination
An HTML <a> with href creates a hyperlink to a target such as a page, a file, or a location on the same page.[1] This is what the product links on this site’s homepage, “Back to notes” on article pages, and “Try the 日序 demo” on the product page do.
They can look like prominent buttons while still rendering as <a>. At these call sites, the shared component receives as="a" and href, keeping the destination in the HTML rather than hiding it inside a click handler.
Readers can then open the content using the browser’s native link operations. The site’s component integration notes already explain that choice. This article focuses on how to decide when placing each control, rather than revisiting the installation process.
These are usage examples, not a complete page. The paths are Chinese-route examples and remain unchanged:
<a href="/products/daily-order">View product</a> <a href="/notes">Back to notes</a>
Moving within a page can also be navigation. On the 日序 introduction page, “Learn how 日序 works” links to #journey, taking the reader to an explanatory section further down. It does not need to become an action button just because it stays on the same page.
Actions change the current state
Opening the article contents drawer does not lead to another content URL. Its job is to open a control within the current page, so this site uses <button type="button">.
Enlarging the avatar on the about page is an action too: it changes the interface state within the same page rather than navigating to an image URL.
HTML’s <button> is an interactive element that can be operated with a mouse, a keyboard, and other input methods.[2] Choosing the right element is only the beginning, though. Drawers and enlarged-image windows still need to handle focus, closing behavior, and state synchronization.
I therefore do not treat “it already uses a button” as evidence that an interaction is complete. A component can provide the appearance and basic structure, but each call site still has to implement the operation its control promises.
Make form submission explicit
type="button" and type="submit" are not optional decoration. In typical form-associated use, a button without an appropriate type may submit the form. Controls that only operate the interface should explicitly use type="button".[2]
When this site’s local Button component renders a <button>, it defaults to type="button". The caller can still explicitly pass type="submit". That is how the current project implements it, not a default shared by all component libraries.
For example, the following illustrates form usage. It does not mean this site has added this form or a storage API:
<form>
<button type="button">Show instructions</button>
<button type="submit">Submit data</button>
</form>
The first button only shows instructions; the second expresses the intent to submit. Data validation, failed requests, and duplicate submissions must be handled by the actual form. The presence of a submit button does not mean those features exist.
Do not let variant choose the element
This site’s Button has both variant="link" and as="a". They control different things.
variant="link" selects the appearance. Without an explicit as, the component still defaults to rendering <button>. Only as="a" switches the element to a link, with the call site supplying href.
This separation lets a text-style action button remain a button, and a prominent page entry retain its navigation semantics. It also means developers cannot judge the element by the variant name alone.
I check against the current component’s contract:
| Intended use | Choice | What to check |
|---|---|---|
| Go to a page or a section on the same page | as="a" |
A real href and the destination content |
| Open or close part of the interface | Default button or as="button" |
type="button", the operation, and its state |
| Submit a form | button with type="submit" |
Form association and the actual submission flow |
This table covers common uses on this site, not every kind of interaction. For example, the toggle for a native details element belongs to summary. Not every clickable area should be forced into either a button or an anchor.
Scripts can enhance a link without replacing it
This site’s article contents render native links with href="#段落識別字". Browser scripts then add scrolling effects, a current-section indicator, and the action that closes the contents drawer on mobile. The literal fragment above is a Chinese identifier example and is retained as written.
The order matters: HTML provides the destination first, and scripts enhance the behavior afterward. The contents are not a set of text items that work only through events, leaving scripts to supply their purpose.
Having real links does not mean all the surrounding controls work without JavaScript. This site’s mobile contents also have a native link list inside noscript; the drawer toggle and scroll indicator still depend on script enhancements. Those behaviors should be verified separately.
Inspect the output, not just the component name
It is hard to tell from the screen whether a rounded control is an <a> or a <button>. I go back to the actual HTML to inspect the tag, href, type, and control name, then check whether they match the intended use.
Next come the interaction checks: whether links reach the article content, buttons really open the contents, icon controls have understandable names, and keyboard behavior fits the operation. Each actual call site needs verification. Success with another button is not a substitute.
Shared styles can reduce duplication, but “view content” and “change state” remain different responsibilities. I want the component to keep the appearance consistent while letting HTML preserve that distinction.
Scope of this note
This article draws on the site’s local shared Button implementation, product-page links, about-page controls, and article contents. The form section is a usage example, not evidence of a new data submission feature on this site. This article also does not claim that every browser, assistive technology, or interaction path has been fully validated. For the history of component integration and isolated testing, see Adding bejamas/ui: start with one Button without letting the component library take over the site (Traditional Chinese).
Sources
[1] https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/a [2] https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/button