@@ -780,4 +780,141 @@ describe('Tour | Step', () => {
780780 } ) ;
781781 } ) ;
782782 } ) ;
783+
784+ describe ( 'tabIndex preservation' , ( ) => {
785+ let instance ;
786+ let testElement ;
787+
788+ beforeEach ( ( ) => {
789+ // Create a test element
790+ testElement = document . createElement ( 'div' ) ;
791+ testElement . id = 'tabindex-test-element' ;
792+ document . body . appendChild ( testElement ) ;
793+
794+ instance = new Shepherd . Tour ( {
795+ steps : [
796+ {
797+ id : 'test-step' ,
798+ text : 'Test step' ,
799+ attachTo : { element : '#tabindex-test-element' , on : 'top' }
800+ }
801+ ]
802+ } ) ;
803+ } ) ;
804+
805+ afterEach ( ( ) => {
806+ instance . complete ( ) ;
807+ testElement ?. remove ( ) ;
808+ } ) ;
809+
810+ it ( 'stores and restores original tabIndex when element has no tabindex attribute' , ( ) => {
811+ // Initially, the element should have no tabindex attribute
812+ expect ( testElement . hasAttribute ( 'tabindex' ) ) . toBe ( false ) ;
813+
814+ // Start the tour
815+ instance . start ( ) ;
816+
817+ // During the tour, tabIndex should be set to 0
818+ expect ( testElement . tabIndex ) . toBe ( 0 ) ;
819+ expect ( testElement . getAttribute ( 'tabindex' ) ) . toBe ( '0' ) ;
820+
821+ // Hide the step
822+ instance . getCurrentStep ( ) . hide ( ) ;
823+
824+ // After hiding, the tabindex attribute should be removed
825+ expect ( testElement . hasAttribute ( 'tabindex' ) ) . toBe ( false ) ;
826+ } ) ;
827+
828+ it ( 'stores and restores original tabIndex when element has tabindex="-1"' , ( ) => {
829+ // Set tabindex to -1 initially
830+ testElement . setAttribute ( 'tabindex' , '-1' ) ;
831+ expect ( testElement . getAttribute ( 'tabindex' ) ) . toBe ( '-1' ) ;
832+
833+ // Start the tour
834+ instance . start ( ) ;
835+
836+ // During the tour, tabIndex should be set to 0
837+ expect ( testElement . tabIndex ) . toBe ( 0 ) ;
838+ expect ( testElement . getAttribute ( 'tabindex' ) ) . toBe ( '0' ) ;
839+
840+ // Hide the step
841+ instance . getCurrentStep ( ) . hide ( ) ;
842+
843+ // After hiding, tabIndex should be restored to -1
844+ expect ( testElement . getAttribute ( 'tabindex' ) ) . toBe ( '-1' ) ;
845+ } ) ;
846+
847+ it ( 'stores and restores original tabIndex when element has tabindex="5"' , ( ) => {
848+ // Set tabindex to 5 initially
849+ testElement . setAttribute ( 'tabindex' , '5' ) ;
850+ expect ( testElement . getAttribute ( 'tabindex' ) ) . toBe ( '5' ) ;
851+
852+ // Start the tour
853+ instance . start ( ) ;
854+
855+ // During the tour, tabIndex should be set to 0
856+ expect ( testElement . tabIndex ) . toBe ( 0 ) ;
857+ expect ( testElement . getAttribute ( 'tabindex' ) ) . toBe ( '0' ) ;
858+
859+ // Hide the step
860+ instance . getCurrentStep ( ) . hide ( ) ;
861+
862+ // After hiding, tabIndex should be restored to 5
863+ expect ( testElement . getAttribute ( 'tabindex' ) ) . toBe ( '5' ) ;
864+ } ) ;
865+
866+ it ( 'restores tabIndex when step is destroyed' , ( ) => {
867+ // Set tabindex to -1 initially
868+ testElement . setAttribute ( 'tabindex' , '-1' ) ;
869+
870+ // Start the tour
871+ instance . start ( ) ;
872+
873+ // During the tour, tabIndex should be set to 0
874+ expect ( testElement . getAttribute ( 'tabindex' ) ) . toBe ( '0' ) ;
875+
876+ // Destroy the step
877+ instance . getCurrentStep ( ) . destroy ( ) ;
878+
879+ // After destroying, tabIndex should be restored to -1
880+ expect ( testElement . getAttribute ( 'tabindex' ) ) . toBe ( '-1' ) ;
881+ } ) ;
882+
883+ it ( 'handles multiple show/hide cycles correctly' , ( ) => {
884+ // Set tabindex to 2 initially
885+ testElement . setAttribute ( 'tabindex' , '2' ) ;
886+
887+ // Start the tour (first show)
888+ instance . start ( ) ;
889+ expect ( testElement . getAttribute ( 'tabindex' ) ) . toBe ( '0' ) ;
890+
891+ // Hide the step
892+ instance . getCurrentStep ( ) . hide ( ) ;
893+ expect ( testElement . getAttribute ( 'tabindex' ) ) . toBe ( '2' ) ;
894+
895+ // Show again
896+ instance . getCurrentStep ( ) . show ( ) ;
897+ expect ( testElement . getAttribute ( 'tabindex' ) ) . toBe ( '0' ) ;
898+
899+ // Hide again
900+ instance . getCurrentStep ( ) . hide ( ) ;
901+ expect ( testElement . getAttribute ( 'tabindex' ) ) . toBe ( '2' ) ;
902+ } ) ;
903+
904+ it ( 'only stores the original value once, not intermediate values' , ( ) => {
905+ // Set tabindex to 3 initially
906+ testElement . setAttribute ( 'tabindex' , '3' ) ;
907+
908+ // Start the tour
909+ instance . start ( ) ;
910+ expect ( testElement . getAttribute ( 'tabindex' ) ) . toBe ( '0' ) ;
911+
912+ // Manually change tabIndex (simulating some other code changing it)
913+ testElement . setAttribute ( 'tabindex' , '7' ) ;
914+
915+ // Hide the step - should restore to original value (3), not intermediate (7)
916+ instance . getCurrentStep ( ) . hide ( ) ;
917+ expect ( testElement . getAttribute ( 'tabindex' ) ) . toBe ( '3' ) ;
918+ } ) ;
919+ } ) ;
783920} ) ;
0 commit comments