Skip to content
This repository has been archived by the owner on Jun 29, 2023. It is now read-only.

refactor: remove tabindex @Prop #267

Merged
merged 2 commits into from
Sep 23, 2019

Conversation

pr3tori4n
Copy link
Contributor

Related Issue: #258

Summary

  • This removes the @prop tabindex.
  • Preserve arrow navigation functionality
  • Respects user-defined tabindex.

Preserve arrow navigation functionality
@pr3tori4n pr3tori4n self-assigned this Sep 16, 2019
@pr3tori4n pr3tori4n requested review from driskull and jcfranco and removed request for driskull September 16, 2019 18:30
@pr3tori4n pr3tori4n added enhancement New feature request for an existing component refactor labels Sep 16, 2019
Copy link
Member

@driskull driskull left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@@ -86,6 +84,8 @@ export class CalciteTipManager {

observer = new MutationObserver(() => this.setUpTips());

tabindex = "0";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is no longer a prop, can this be renamed to something a bit more expressive? initialTabIndexAttr?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It stores both the initial value and then the overridden value if one is present. so initialTabIndex is a misnomer.
There another name you prefer that's more descriptive?

@@ -242,7 +245,7 @@ export class CalciteTipManager {
return <Host />;
}
return (
<Host onKeydown={this.tipManagerKeyDownHandler}>
<Host onKeydown={this.tipManagerKeyDownHandler} tabindex={this.tabindex}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do still prefer having a container inside the custom element to handle the tabindex that way we are not modifying the tabindex on the host node. We should probably be keeping that logic internal to the component.

It's also more consistent with how a native element works. For example, a button doesn't automatically get a tabIndex but it is focusable by nature due to its internals.

Copy link
Contributor Author

@pr3tori4n pr3tori4n Sep 18, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can override the default tabindex of button. By keeping the tabindex on the host, we allow that same override here. If we put the tabindex on a child container and ignore the tabindex on the host, then the user loses the ability to override the tabindex.

<button>normal button</button>
<button tabindex="-1">can't focus</button>

<calcite-tip-manager>normal tip manager</calcite-tip-manager>
<calcite-tip-manager tabindex="-1">can't focus</calcite-tip-manager>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we put the tabindex on a child container and ignore the tabindex on the host, then the user loses the ability to override the tabindex.

That's not true, if the user sets tabindex="-1" on the host it won't receive focus through tabbing, nor will its children.

This is exactly how the calcite-action works.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://codepen.io/pr3tori4n/pen/VwZEEGv

Tried it in this pen. tabindex="-1" in the outer div doesn't prevent focus on the inner div

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These work the same:

<style>
          .testClass {
            font-family: var(--calcite-app-font-family);
            display: flex;
            color: var(--calcite-app-foreground);
            fill: var(--calcite-app-foreground);
            background-color: var(--calcite-app-background);
            border-radius: var(--calcite-app-border-radius);
            padding: var(--calcite-app-cap-spacing-three-quarters) var(--calcite-app-side-spacing-three-quarters);
            margin: 0;
            justify-content: flex-start;
            align-items: center;
            border: none;
            width: auto;
            cursor: pointer;
            font-size: var(--calcite-app-font-size--1);
            line-height: normal;
            transition: color 125ms ease-in-out, fill 125ms ease-in-out, background-color 125ms ease-in-out;
            text-align: unset;
            position: relative;
          }
        </style>

        <button class="testClass" tabindex="-1">test</button>

        <calcite-action tabindex="-1" text="hello world" text-enabled></calcite-action>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently, shadowDom works differently. There's a whole issue here:
WICG/webcomponents#774

But basically this:

Setting tabindex=-1 on a shadow host as the effect of disabling the focus of the component. We have builtin elements like input and video elements, and if tabindex=-1 is set on either element, then its content including buttons and media controls aren't focusable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems there are many people suggesting this is unexpected behavior. This may end up changing.

Copy link
Member

@driskull driskull left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should be consistent with the calcite-action and not set a tabIndex on the host.

@@ -94,6 +94,9 @@ export class CalciteTipManager {

connectedCallback() {
this.setUpTips();
if (this.el.hasAttribute("tabindex")) {
this.tabindex = this.el.getAttribute("tabindex");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should be consistent with the calcite-action and not set a tabIndex on the host.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may also be related: ionic-team/stencil#1008

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pr3tori4n
Copy link
Contributor Author

Ok adding a wrapping element with tabindex set to 0. @asangma @kat10140 just an FYI that this means the tip manager will always be a focusable element in the tab order. There will be no way to override this. If that's desired, we'll need to make modifications.

Copy link
Member

@driskull driskull left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

</header>
<div class={classnames(CSS.tipContainer, this.direction)} key={this.selectedIndex}>
<slot />
<Host onKeydown={this.tipManagerKeyDownHandler}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: you could move the onKeyDown to the element that receives focus but it will bubble up in this case.

@driskull
Copy link
Member

the tip manager will always be a focusable element in the tab order.

A user can add a tabIndex="-1" to the calcite-tip-manager to avoid keyboard tabbing into it.

@pr3tori4n pr3tori4n merged commit cd8bdd4 into master Sep 23, 2019
@pr3tori4n pr3tori4n deleted the hrobbins/refactor-remove-tabindex-prop-258 branch September 23, 2019 17:38
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature request for an existing component refactor
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants