skip to Main Content

when i click on a link to navigate to certain page , if i press the tab key, focus starts on a browser elements (search bar), not at the top of a new page like a visually-impaired user would expect even i set the tab-index value?
but it works fine when i reload the page
this is my page component

    @Component({
  selector: 'app-rental-contracts-page',
  template: '<router-outlet></router-outlet>',
  host: {
    class:'lc-grid__item--wrapper'

  }
})
export class RentalContractsPageComponent implements OnInit {

  constructor() { 
  }

  ngOnInit() {
  }

}

and this my module

const routes: Routes = [
  {
    path: '',
    component: RentalContractsPageComponent,
    children: [
      {
        path: '',
        component: RentalContractsListPageComponent,
        data: { title: "Baux" },
      },
      {
        path: 'term/:term',
        component: RentalContractsListPageComponent
      },
      {
        path: 'create',
        component: CreateRentalContractPageComponent
      },
      {
        path: 'create/:ownerId',
        component: CreateRentalContractPageComponent
      }
      ,
      {
        path: 'create/:ownerId/:partId',
        component: CreateRentalContractPageComponent
      }

    ]
  }
];


@NgModule({
  declarations: [RentalContractsPageComponent, CreateRentalContractPageComponent, RentalContractsListPageComponent],
  imports: [
    CommonModule,
    RouterModule.forChild(routes),
    TranslateModule,
    NgbModule,
    FormsModule,
    ContractsModule.forRoot(environment),
  ]
})
export class RentalContractsPageModule { }

2

Answers


  1. When you load a component, ensure you have a ViewChild on the element that you want to focus, this can also be a plain div tag

    When you focus, the tabIndex will continue from the point of focus, is my solution for this issue!

    HTML

    <div #element tabindex="0">
       <!-- content located inside here -->
       ...
    </div>
    

    TS

    @ViewChild('element') element: ElementRef<any>;
    ...
    
    ...
    ngAfterViewInit() {
        if(element?.nativeElement) {
            element.nativeElement.focus();
        }
    }
    
    Login or Signup to reply.
  2. Create an element that has a tabindex of -1. Because the value is -1, it won’t be focusable via tab, but it can be focusable via JavaScript. Also note, any non-standard element (input, button, textarea, etc.) with a tabindex attribute also must also have a role attribute to be valid so that a screen reader knows how it should interact with the element.

    Here is a working example.

    Lets create a reusable directive to do this we will call it autofocus to have it work similar to a native HTML element. We will also add two inputs/bindings one for a custom tabindex which we will default to -1, and one for a custom role which we will default to region.

    @Directive({
      selector: '[autofocus]',
      standalone: true
    })
    export class AutoFocus implements AfterViewInit {
      @HostBinding('attr.tabindex') tabIndexBinding = '-1';
      @HostBinding('attr.role') roleBinding = 'region';
    
      // Note: We add the inputs otherwise we cannot set our own values. 
      // The HostBinding would then just overwrite tabindex/role with its default value.
      @Input() set tabindex(value: string) { this.tabIndexBinding = value; }
      @Input() set role(value: string) { this.roleBinding = value; }
    
      constructor(readonly elementRef: ElementRef) {}
    
      ngAfterViewInit() {
        this.elementRef.nativeElement.focus();
      }
    }
    

    Note: Since you can have only one activeElement per page, if you use more than one on the same page, then the last directive created will be the focused element.

    Next, lets import it into our component and add the autofocus attribute to it.

    Here is how you can (optionally) style your input elements. I disabled styling on all elements except for the input in this example:

    • Disable outline on everything with * {outline: none;}
    • Add a custom outline to the input with :focus-visible
    @Component({
      selector: 'app-root',
      standalone: true,
      imports: [AutoFocus],
      styles: `
      * {
        outline: none;
      }
      input {
        border-radius: 5px;
        padding: 4px;
        border: solid 1px #ccc;
      
        &:focus-visible {
          outline: solid 2px blue;
          outline-offset: 2px;
        }
      }
      `,
      template: `
        <div autofocus>
          <input type="text" />
        </div>
      `,
    })
    export class App implements AfterViewInit {
      ngAfterViewInit() {
        console.log(document.activeElement);
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search