How to suppress anchor tag click redirection in customizer preview frame?

Update: The fix here has been incorporated into WordPress Core trunk for the upcoming 4.5 release (now in alpha). See r36371.


I think the problem with the unbinding of the event handler is that it is being done too early. Try doing it at the preview-ready Customizer event. For example, enqueue the following JS in your Customizer preview (with customize-preview as a script dependeny) which short-circuits the click.preview logic if the link clicked has an in-page link target or if it uses the javascript: protocol:

if ( /\/customize\.php$/.test( window.location.pathname ) ) {
    wp.customize.bind( 'preview-ready', function() {
        var body = $( 'body' );
        body.off( 'click.preview' );
        body.on( 'click.preview', 'a[href]', function( event ) {
            var link = $( this );
            if ( /^(#|javascript:)/.test( link.attr( 'href' ) ) ) {
                return;
            }
            event.preventDefault();
            wp.customize.preview.send( 'scroll', 0 );
            wp.customize.preview.send( 'url', link.prop( 'href' ) );
        });
    } );
}

The inclusion of the href type really should be part of Core and I’ll add it to my todo list to get that committed as part of the 4.5 cycle.

Note the test for customize.php is to ensure that transactions with the natural URL being used as the Customizer preview iframe URL hasn’t been implemented yet, because that change will mean changes to the click.preview logic.