The Link
component is a clickable control primarily used for navigation, providing an interactive reference to a resource. It is usually displayed as an inline element by default that can wrap text if it goes past the edges of its parent.
The following section documents variants of the component that currently exist in Fabric and identifies variants that exist in other component libraries but don't currently exist in Fabric, documenting which component libraries have those variants.
Link rendered as an anchor
Link rendered as a button
- Removing this variant by default from Fluent UI, if people want it they can use the
slots
or theas
prop.
- Removing this variant by default from Fluent UI, if people want it they can use the
Block/Non-inline link
- In Carbon Design
- In Gestalt
External link
- In Chakra UI
The following section documents links to different UI libraries implementations of Links, while also providing a code sandbox with a side by side implementation of them for comparison.
-
FastDNA Link (Hypertext)
The following section documents the properties that will become part of the new component, as well as the process for mitigating all changes when moving from Fabric and Stardust to Fluent UI.
Name | Type | Default value | Required? | Description |
---|---|---|---|---|
ariaDescribedBy |
string |
No | Identifies the element (or elements) that describes the object. | |
ariaHidden |
boolean |
false |
No | Indicates whether the element is exposed to an accessibility API. |
ariaLabel |
string |
No | Defines a string value that labels the current element. | |
ariaLabelledBy |
string |
No | Identifies the element (or elements) that labels the current element. | |
className |
string |
No | Defines an additional classname to provide on the root of the Link . |
|
componentRef |
IRefObject<ILink> |
No | Defines an optional reference to access the imperative interface of the Link . |
|
disabled |
boolean |
false |
No | Defines whether the Link is in an enabled or disabled state. |
href |
string |
Yes | Defines an href that serves as the navigation destination when clicking on the Link . |
|
onClick |
(ev: MouseEvent) => void |
No | Defines a callback that handles the processing of click events on the Link . |
|
role |
string |
No | Defines the accessibility role of the Link . |
Props no outlined above are not handled and should be spread in the root
slot of the component.
Name | Type | Default value | Description |
---|---|---|---|
focus |
() => void |
Sets focus on the Link . |
None at the moment.
https://developer.microsoft.com/en-us/fabric#/controls/web/link
Name | Type | Notes |
---|---|---|
focus |
() => void |
Name | Type | Notes |
---|---|---|
as |
string | React.ComponentClass | React.StatelessComponent |
Remove as prop in new component. |
componentRef |
IRefObject<ILink> |
|
disabled |
boolean |
|
keytipProps |
IKeytipProps |
Should be removed until we add Keytips in Fluent UI. |
styles |
IStyleFunctionOrObject<ILinkStyleProps, ILinkStyles> |
Should be deprecated in favor of recomposition. |
theme |
ITheme |
Should not show up in the public props contract. |
Stardust does not currently have a Link
component implementation.
Name | Action to take/taken | Property transitioned? | Breaking change? | Codemod/Shim created? |
---|---|---|---|---|
focus |
TBD | ❌ | ❌ | ❌ |
Name | Action to take/taken | Property transitioned? | Breaking change? | Codemod/Shim created? |
---|---|---|---|---|
as |
TBD | ❌ | ❌ | ❌ |
componentRef |
TBD | ❌ | ❌ | ❌ |
disabled |
TBD | ❌ | ❌ | ❌ |
keytipProps |
TBD | ❌ | ❌ | ❌ |
styles |
TBD | ❌ | ❌ | ❌ |
theme |
TBD | ❌ | ❌ | ❌ |
Stardust does not currently have a Link
component implementation.
The following section documents the DOM structure for the component from different component library examples and then suggests a recommended DOM taking into consideration common patterns between the libraries reviewed.
<a data-baseweb="link" href="https://baseweb.design" class="k5 ah eq bk er es bb bc tf tg th"> Link to Base Web </a>
None.
<a href="#" class="bx--link some-class">Link</a>
- Renders by default as a block, and not an inline, element.
<a href="https=//chakra-ui.com" class="css-u5zpo1">Chakra UI</a>
None.
<a href="http://dev.office.com/fabric/components/link" class="ms-Link root-109"> it renders as an anchor tag. </a>
<button type="button" class="ms-Link root-163">the link is rendered as a button</button>
Links
without anhref
provided render asbuttons
.
<a href="https://www.bing.com" class="c012">Hypertext</a>
None.
<a class="Wk9 xQ4 WMU iyn ljY kVc" href="https://pinterest.com">click here</a>
- Renders by default as a block, and not an inline, element.
<a class="MuiTypography-root MuiLink-root MuiLink-underlineHover jss243 MuiTypography-colorPrimary" href="#"> Link </a>
<button
class="MuiTypography-root MuiLink-root MuiLink-underlineHover MuiLink-button MuiTypography-body2 MuiTypography-colorPrimary"
>
Button Link
</button>
Links
without anhref
provided render asbuttons
.
After looking at all the component libraries above and taking into consideration common patterns the following DOM is recommended.
<a class="root" href="{href}">{children}</a>
If the link is recomposed to use another tag that is not a
for its root
slot, then role="link"
should be added to the root. An example using button
can be read below:
<button class="root" href="{href}" role="link">{children}</button>
From the recommended DOM above we can indicate which slots are going to be required:
Name | Considerations |
---|---|
root |
- What about inline vs block links? Should we provide them as well?
- Maybe different styled variant via recomposition.
Aria spec: https://www.w3.org/TR/wai-aria-1.1/#link https://www.w3.org/TR/wai-aria-practices/#link
The following section describes the different states in which a Link
can be throughout the course of interaction with it.
An enabled Link
communicates interaction by having styling that invite the user to click/tap on it to navigate through content.
A disabled Link
is non-interactive, disallowing the user to click/tap on it to navigate through content.
Typically disabled browser elements do now allow focus. This makes the control difficult for a blind user to know about it, or why it's disabled, without scanning the entire page. Therefore it is recommended to allow focus on disabled components and to make them readonly. This means we use ariaDisabled
attributes, and not disabled
attributes, for defining a disabled state. This may sometimes require special attention to ignoring input events in the case a browser element might do something. In the past we've introduced an allowDisabledFocus
prop for component users to control this behavior.
A hovered Link
changes styling to communicate that the user has placed a cursor above it.
A focused Link
changes styling to communicate that the user has placed keyboard focus on it. This styling is usually the same to the one in the hovered state plus extra styling on the outline to indicate keyboard focus has been placed on the component.
None.
The following is a set of keys that interact with the Link
component:
Key | Description |
---|---|
Enter |
Executes the Link and moves focus to the Link target. |
Shift + F10 (Optional) |
Opens a context menu for the Link . |
Test: Possible to use this to capture mouse, though Safari does not have compatibility: https://developer.mozilla.org/en-US/docs/Web/API/Element/setPointerCapture
mouseenter
: Should immediately change the styling of theLink
so that it appears to be hovered.mouseleave
: Should immediately remove the hovered styling of theLink
.mouseup
: If triggered while cursor is still inside of theLink's
boundaries, then it should execute theLink
and move focus to theLink
target.
The same behavior as above translated for touch events. This means that there is no equivalent for mouseenter
and mouseleave
, which makes it so that the hovered state cannot be accessed.
- Should default to render a native
a
element unless anotherroot
slot has been specified. - Should mix in the native props expected for the
a
native element. - Should be keyboard tabbable and focusable.
The ariaLabel
, ariaLabelledby
and ariaDescribedBy
properties are surfaced to the component interface but are required to be set by the component user to meet accessibility requirements.
The Link
component uses react-texture
to provide a recomposable implementation that has no runtime performance penalties. The BaseLink
implementation can be used to provide new slots
and default props
without the application of additional styling:
const FooLink = BaseLink.compose({
tokens: {},
styles: {},
slots: {}
});
render () {
<FooLink href="https://www.bing.com">
Go to bing!
</FooLink>
}
1 per slot 1 per state, tagged on root
Tokens represent the general look and feel of the various visual slots. Tokens feed into the styling at the right times in the right slot.
Regarding naming conventions, use a camelCased name following this format:
{slot}{property}{state (or none for default)}
. For example:thumbSizeHovered
.Common property names:
size
,background
,color
,borderRadius
Common states:
hovered
,pressed
,focused
,checked
,checkedHovered
,disabled
Name | Considerations |
---|---|
background |
|
backgroundDisabled |
|
backgroundHovered |
|
backgroundPressed |
|
backgroundVisited |
|
color |
|
colorDisabled |
|
colorHovered |
|
colorPressed |
|
colorVisited |
|
fontFamily |
|
fontSize |
|
fontWeight |
|
textDecoration |
|
textDecorationDisabled |
|
textDecorationHovered |
|
textDecorationPressed |
|
textDecorationVisited |
- What do we do about high contrast? Do we provide additional tokens?
TODO: Example use cases
TODO: If this component represents a selected value, how will that be used in an HTML form? Is there a code example to illustrate?
TODO: Is it possible this component could be rendered in a focus zone? If so, should the focus model change in that case?