Skip to content

Files

Latest commit

 

History

History
402 lines (259 loc) · 15.7 KB

Link.md

File metadata and controls

402 lines (259 loc) · 15.7 KB

Link component specification

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.

Related variant considerations

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.

Variants existing in Fabric today

  • 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 the as prop.

Variants not in Fabric but that exist in other component libraries

  • Block/Non-inline link
    • In Carbon Design
    • In Gestalt
  • External link
    • In Chakra UI

Reference implementations

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.

Props

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.

Recommended component props

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.

Recommended interface props

Name Type Default value Description
focus () => void Sets focus on the Link.

Props to be discussed

None at the moment.

Fabric Link props

https://developer.microsoft.com/en-us/fabric#/controls/web/link

ILink interface

Name Type Notes
focus () => void

ILinkProps interface

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 Link props

Stardust does not currently have a Link component implementation.

Conversion process from Fabric 7 to Fluent UI Link

ILink interface

Name Action to take/taken Property transitioned? Breaking change? Codemod/Shim created?
focus TBD

ILinkProps interface

Name Action to take/taken Property transitioned? Breaking change? Codemod/Shim created?
as TBD
componentRef TBD
disabled TBD
keytipProps TBD
styles TBD
theme TBD

Conversion process from Stardust to Fluent UI Link

Stardust does not currently have a Link component implementation.

DOM Structure

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.

Base Web Link

Example DOM

<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>

Considerations

None.

Carbon Design Link

Example DOM

<a href="#" class="bx--link some-class">Link</a>

Considerations

  • Renders by default as a block, and not an inline, element.

Chakra UI Link

Example DOM

<a href="https=//chakra-ui.com" class="css-u5zpo1">Chakra UI</a>

Considerations

None.

Fabric Link

Example DOM

With href
<a href="http://dev.office.com/fabric/components/link" class="ms-Link root-109"> it renders as an anchor tag. </a>
Without href
<button type="button" class="ms-Link root-163">the link is rendered as a button</button>

Considerations

  • Links without an href provided render as buttons.

FastDNA Link (Hypertext)

Example DOM

<a href="https://www.bing.com" class="c012">Hypertext</a>

Considerations

None.

Gestalt Link

Example DOM

<a class="Wk9 xQ4 WMU iyn ljY kVc" href="https://pinterest.com">click here</a>

Considerations

  • Renders by default as a block, and not an inline, element.

Material-UI Link

Example DOM

With href
<a class="MuiTypography-root MuiLink-root MuiLink-underlineHover jss243 MuiTypography-colorPrimary" href="#"> Link </a>
Without href
<button
  class="MuiTypography-root MuiLink-root MuiLink-underlineHover MuiLink-button MuiTypography-body2 MuiTypography-colorPrimary"
>
  Button Link
</button>

Considerations

  • Links without an href provided render as buttons.

Recommended DOM

After looking at all the component libraries above and taking into consideration common patterns the following DOM is recommended.

For default links

<a class="root" href="{href}">{children}</a>

For recomposed links

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>

Slots

From the recommended DOM above we can indicate which slots are going to be required:

Name Considerations
root

Considerations that need discussion

  • What about inline vs block links? Should we provide them as well?
    • Maybe different styled variant via recomposition.

Behaviors

Aria spec: https://www.w3.org/TR/wai-aria-1.1/#link https://www.w3.org/TR/wai-aria-practices/#link

Fluent UI HIG: https://microsoft.sharepoint-df.com/:w:/r/teams/OPGUXLeads/_layouts/15/Doc.aspx?sourcedoc=%7BE585806E-01BF-4F37-BF59-12708E4CE81D%7D&file=Links.docx&action=default&mobileredirect=true

States

The following section describes the different states in which a Link can be throughout the course of interaction with it.

Enabled state

An enabled Link communicates interaction by having styling that invite the user to click/tap on it to navigate through content.

Disabled state

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.

Hovered state

A hovered Link changes styling to communicate that the user has placed a cursor above it.

Focused state

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.

States that need discussion

None.

Keyboard interaction

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.

Cursor interaction

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 the Link so that it appears to be hovered.
  • mouseleave: Should immediately remove the hovered styling of the Link.
  • mouseup: If triggered while cursor is still inside of the Link's boundaries, then it should execute the Link and move focus to the Link target.

Touch interaction

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.

Screen reader accessibility

root:

  • Should default to render a native a element unless another root slot has been specified.
  • Should mix in the native props expected for the a native element.
  • Should be keyboard tabbable and focusable.

Accessibility concerns for the user.

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.

Themability and customization

Composition

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>
}

Class names

1 per slot 1 per state, tagged on root

Component design tokens

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

To be discussed

  • What do we do about high contrast? Do we provide additional tokens?

Use cases

TODO: Example use cases

Compatibility with other libraries

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?