Theming Views in Drupal 8 with custom templates

TLDR;
To use a custom template for a view in Drupal 8 use this theme naming pattern:

views-view--[view name]--[view display].html.twig

So for Taxonomy view page:

views-view--taxonomy--page.html.twig

Taxonomy view template example

Drupal 8 ships with a Taxonomy View. It's a fairly simple view implementing a Contextual Filter to display all content associated with a particular term id.

For the path, mydomain.com/taxonomy/term/5 the view will grab the id (5) from the current path and query for nodes tagged with it.

But by default, this (and every other view) is themed through view-views.html.twig. That's not what I want. Like most things in Drupal land, you can render this individual view through a custom template.

How do I name a view template in Drupal 8?

I checked Twig debug in my browser inspector looking for the exact naming convention for view templates. That always lists template suggestions. Not this time.

I checked the Taxonomy view config (in Drupal 7 theme hook suggestions were listed there). Theming suggestions have been removed from Views UI in Drupal 8.

Time to read documentation!! :(

Drupal Views Template Documentation

All/most of the resources you need for view template naming you can find in the Views Template Documentation for Drupal 8.

Choose tha naming pattern that fits your purpose. In our example I want to template the main view display. There are also options for view format style and view row style.

Now, create the Twig template file named precisely for your custom view. 

views-view--taxonomy--page.html.twig

If I was theming the Taxonomy block, it would be:

views-view--taxonomy--block.html.twig

Paste in the related Twig markup from the default Drupal template views-view.html.twig :

{#
/**
 * @file
 * Default theme implementation for main view template.
 *
 * Available variables:
 * - attributes: Remaining HTML attributes for the element.
 * - css_name: A css-safe version of the view name.
 * - css_class: The user-specified classes names, if any.
 * - header: The optional header.
 * - footer: The optional footer.
 * - rows: The results of the view query, if any.
 * - empty: The content to display if there are no rows.
 * - pager: The optional pager next/prev links to display.
 * - exposed: Exposed widget form/info to display.
 * - feed_icons: Optional feed icons to display.
 * - more: An optional link to the next page of results.
 * - title: Title of the view, only used when displaying in the admin preview.
 * - title_prefix: Additional output populated by modules, intended to be
 *   displayed in front of the view title.
 * - title_suffix: Additional output populated by modules, intended to be
 *   displayed after the view title.
 * - attachment_before: An optional attachment view to be displayed before the
 *   view content.
 * - attachment_after: An optional attachment view to be displayed after the
 *   view content.
 * - dom_id: Unique id for every view being printed to give unique class for
 *   Javascript.
 *
 * @see template_preprocess_views_view()
 *
 * @ingroup themeable
 */
#}
{%
  set classes = [
    dom_id ? 'js-view-dom-id-' ~ dom_id,
  ]
%}
<div{{ attributes.addClass(classes) }}>
  {{ title_prefix }}
  {{ title }}
  {{ title_suffix }}

  {% if header %}
    <header>
      {{ header }}
    </header>
  {% endif %}

  {{ exposed }}
  {{ attachment_before }}

  {{ rows }}
  {{ empty }}
  {{ pager }}

  {{ attachment_after }}
  {{ more }}

  {% if footer %}
    <footer>
      {{ footer }}
    </footer>
  {% endif %}

  {{ feed_icons }}
</div>

You can start from nothing, but it's a lot easier to have the default code and modify, rearrange or delete as necessary. 

Make your code changes

Clear cache and you're all done.