Repository: pydata/xarray

Issue:
Add welcome bot?
### Is your feature request related to a problem?

Given all the outreachy interest (and perhaps just in general) it may be nice to enable a [welcome bot](https://github.com/apps/welcome) like on the Jupyter repos

### Describe the solution you'd like

_No response_

### Describe alternatives you've considered

_No response_

### Additional context

_No response_

Discussion:
nishtha981: Hey! @dcherian @TomNicholas 
Under which heading in the "what's new.rst" do I put this change under? Internal Changes? 
nishtha981: heyy!
@dcherian @TomNicholas 
Could you please review my pr?
Thanks!
nishtha981: @headtr1ck 
I tried out the bot on a repo of mine.
It worked there. 
I then changed the messages on the bot.

<img width="656" alt="image" src="https://user-images.githubusercontent.com/92522516/229365331-1ebf63ef-038c-41cc-aa78-564dcb600576.png">

headtr1ck: Oh, you can add an entry in whats-new if you want!
nishtha981: > Oh, you can add an entry in whats-new if you want!

Hey! @headtr1ck 
I've added the changes to the what's new file.
Please do review it!
Thanks!

Patch:
diff --git a/.github/config.yml b/.github/config.yml
new file mode 100644
index 00000000..c64c2e28
--- /dev/null
+++ b/.github/config.yml
@@ -0,0 +1,23 @@
+# Comment to be posted to on first time issues
+newIssueWelcomeComment: >
+  Thanks for opening your first issue here at xarray! Be sure to follow the issue template!
+
+  If you have an idea for a solution, we would really welcome a Pull Request with proposed changes.
+
+  See the [Contributing Guide](https://docs.xarray.dev/en/latest/contributing.html) for more.
+
+  It may take us a while to respond here, but we really value your contribution. Contributors like you help make xarray better.
+
+  Thank you!
+
+# Comment to be posted to on PRs from first time contributors in your repository
+newPRWelcomeComment: >
+  Thank you for opening this pull request! It may take us a few days to respond here, so thank you for being patient.
+
+  If you have questions, some answers may be found in our [contributing guidelines](http://docs.xarray.dev/en/stable/contributing.html).
+
+# Comment to be posted to on pull requests merged by a first time user
+firstPRMergeComment: >
+  Congratulations on completing your first pull request! Welcome to Xarray!
+  We are proud of you, and hope to see you again!
+  ![celebration gif](https://media.giphy.com/media/umYMU8G2ixG5mJBDo5/giphy.gif)
diff --git a/.github/workflows/pypi-release.yaml b/.github/workflows/pypi-release.yaml
index a1e38644..31724033 100644
--- a/.github/workflows/pypi-release.yaml
+++ b/.github/workflows/pypi-release.yaml
@@ -72,7 +72,7 @@ jobs:
 
       - name: Publish package to TestPyPI
         if: github.event_name == 'push'
-        uses: pypa/gh-action-pypi-publish@v1.8.3
+        uses: pypa/gh-action-pypi-publish@v1.8.4
         with:
           user: __token__
           password: ${{ secrets.TESTPYPI_TOKEN }}
@@ -90,7 +90,7 @@ jobs:
           name: releases
           path: dist
       - name: Publish package to PyPI
-        uses: pypa/gh-action-pypi-publish@v1.8.3
+        uses: pypa/gh-action-pypi-publish@v1.8.4
         with:
           user: __token__
           password: ${{ secrets.PYPI_TOKEN }}
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 45c15da8..13517a6a 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -16,13 +16,13 @@ repos:
         files: ^xarray/
   - repo: https://github.com/charliermarsh/ruff-pre-commit
     # Ruff version.
-    rev: 'v0.0.259'
+    rev: 'v0.0.260'
     hooks:
       - id: ruff
         args: ["--fix"]
   # https://github.com/python/black#version-control-integration
   - repo: https://github.com/psf/black
-    rev: 23.1.0
+    rev: 23.3.0
     hooks:
       - id: black
       - id: black-jupyter
@@ -31,7 +31,7 @@ repos:
     hooks:
       - id: blackdoc
         exclude: "generate_aggregations.py"
-        additional_dependencies: ["black==23.1.0"]
+        additional_dependencies: ["black==23.3.0"]
       - id: blackdoc-autoupdate-black
   - repo: https://github.com/pre-commit/mirrors-mypy
     rev: v1.1.1
diff --git a/doc/api.rst b/doc/api.rst
index e46bd8bc..d180aa66 100644
--- a/doc/api.rst
+++ b/doc/api.rst
@@ -642,6 +642,7 @@ DataArray methods
    DataArray.to_numpy
    DataArray.to_pandas
    DataArray.to_series
+   DataArray.to_zarr
    DataArray.chunk
    DataArray.close
    DataArray.compute
diff --git a/doc/getting-started-guide/faq.rst b/doc/getting-started-guide/faq.rst
index 08cb9646..e0e44dc7 100644
--- a/doc/getting-started-guide/faq.rst
+++ b/doc/getting-started-guide/faq.rst
@@ -356,6 +356,25 @@ There may be situations where you need to specify the engine manually using the
 
 Some packages may have additional functionality beyond what is shown here. You can refer to the documentation for each package for more information.
 
+How does xarray handle missing values?
+--------------------------------------
+
+**xarray can handle missing values using ``np.NaN``**
+
+- ``np.NaN`` is  used to represent missing values in labeled arrays and datasets. It is a commonly used standard for representing missing or undefined numerical data in scientific computing. ``np.NaN`` is a constant value in NumPy that represents "Not a Number" or missing values.
+
+- Most of xarray's computation methods are designed to automatically handle missing values appropriately.
+
+  For example, when performing operations like addition or multiplication on arrays that contain missing values, xarray will automatically ignore the missing values and only perform the operation on the valid data. This makes it easy to work with data that may contain missing or undefined values without having to worry about handling them explicitly.
+
+- Many of xarray's `aggregation methods <https://docs.xarray.dev/en/stable/user-guide/computation.html#aggregation>`_, such as ``sum()``, ``mean()``, ``min()``, ``max()``, and others, have a skipna argument that controls whether missing values (represented by NaN) should be skipped (True) or treated as NaN (False) when performing the calculation.
+
+  By default, ``skipna`` is set to `True`, so missing values are ignored when computing the result. However, you can set ``skipna`` to `False` if you want missing values to be treated as NaN and included in the calculation.
+
+- On `plotting <https://docs.xarray.dev/en/stable/user-guide/plotting.html#missing-values>`_ an xarray dataset or array that contains missing values, xarray will simply leave the missing values as blank spaces in the plot.
+
+- We have a set of `methods <https://docs.xarray.dev/en/stable/user-guide/computation.html#missing-values>`_ for manipulating missing and filling values.
+
 How should I cite xarray?
 -------------------------
 
diff --git a/doc/user-guide/computation.rst b/doc/user-guide/computation.rst
index f913ea41..d1f1274c 100644
--- a/doc/user-guide/computation.rst
+++ b/doc/user-guide/computation.rst
@@ -68,28 +68,112 @@ Data arrays also implement many :py:class:`numpy.ndarray` methods:
 Missing values
 ==============
 
+Xarray represents missing values using the "NaN" (Not a Number) value from NumPy, which is a
+special floating-point value that indicates a value that is undefined or unrepresentable.
+There are several methods for handling missing values in xarray:
+
 Xarray objects borrow the :py:meth:`~xarray.DataArray.isnull`,
 :py:meth:`~xarray.DataArray.notnull`, :py:meth:`~xarray.DataArray.count`,
 :py:meth:`~xarray.DataArray.dropna`, :py:meth:`~xarray.DataArray.fillna`,
 :py:meth:`~xarray.DataArray.ffill`, and :py:meth:`~xarray.DataArray.bfill`
 methods for working with missing data from pandas:
 
+:py:meth:`~xarray.DataArray.isnull` is a method in xarray that can be used to check for missing or null values in an xarray object.
+It returns a new xarray object with the same dimensions as the original object, but with boolean values
+indicating where **missing values** are present.
+
 .. ipython:: python
 
     x = xr.DataArray([0, 1, np.nan, np.nan, 2], dims=["x"])
     x.isnull()
+
+In this example, the third and fourth elements of 'x' are NaN, so the resulting :py:class:`~xarray.DataArray`
+object has 'True' values in the third and fourth positions and 'False' values in the other positions.
+
+:py:meth:`~xarray.DataArray.notnull` is a method in xarray that can be used to check for non-missing or non-null values in an xarray
+object. It returns a new xarray object with the same dimensions as the original object, but with boolean
+values indicating where **non-missing values** are present.
+
+.. ipython:: python
+
+    x = xr.DataArray([0, 1, np.nan, np.nan, 2], dims=["x"])
     x.notnull()
+
+In this example, the first two and the last elements of x are not NaN, so the resulting
+:py:class:`~xarray.DataArray` object has 'True' values in these positions, and 'False' values in the
+third and fourth positions where NaN is located.
+
+:py:meth:`~xarray.DataArray.count` is a method in xarray that can be used to count the number of
+non-missing values along one or more dimensions of an xarray object. It returns a new xarray object with
+the same dimensions as the original object, but with each element replaced by the count of non-missing
+values along the specified dimensions.
+
+.. ipython:: python
+
+    x = xr.DataArray([0, 1, np.nan, np.nan, 2], dims=["x"])
     x.count()
+
+In this example, 'x' has five elements, but two of them are NaN, so the resulting
+:py:class:`~xarray.DataArray` object having a single element containing the value '3', which represents
+the number of non-null elements in x.
+
+:py:meth:`~xarray.DataArray.dropna` is a method in xarray that can be used to remove missing or null values from an xarray object.
+It returns a new xarray object with the same dimensions as the original object, but with missing values
+removed.
+
+.. ipython:: python
+
+    x = xr.DataArray([0, 1, np.nan, np.nan, 2], dims=["x"])
     x.dropna(dim="x")
+
+In this example, on calling x.dropna(dim="x") removes any missing values and returns a new
+:py:class:`~xarray.DataArray` object with only the non-null elements [0, 1, 2] of 'x', in the
+original order.
+
+:py:meth:`~xarray.DataArray.fillna` is a method in xarray that can be used to fill missing or null values in an xarray object with a
+specified value or method. It returns a new xarray object with the same dimensions as the original object, but with missing values filled.
+
+.. ipython:: python
+
+    x = xr.DataArray([0, 1, np.nan, np.nan, 2], dims=["x"])
     x.fillna(-1)
+
+In this example, there are two NaN values in 'x', so calling x.fillna(-1) replaces these values with -1 and
+returns a new :py:class:`~xarray.DataArray` object with five elements, containing the values
+[0, 1, -1, -1, 2] in the original order.
+
+:py:meth:`~xarray.DataArray.ffill` is a method in xarray that can be used to forward fill (or fill forward) missing values in an
+xarray object along one or more dimensions. It returns a new xarray object with the same dimensions as the
+original object, but with missing values replaced by the last non-missing value along the specified dimensions.
+
+.. ipython:: python
+
+    x = xr.DataArray([0, 1, np.nan, np.nan, 2], dims=["x"])
     x.ffill("x")
+
+In this example, there are two NaN values in 'x', so calling x.ffill("x") fills these values with the last
+non-null value in the same dimension, which are 0 and 1, respectively. The resulting :py:class:`~xarray.DataArray` object has
+five elements, containing the values [0, 1, 1, 1, 2] in the original order.
+
+:py:meth:`~xarray.DataArray.bfill` is a method in xarray that can be used to backward fill (or fill backward) missing values in an
+xarray object along one or more dimensions. It returns a new xarray object with the same dimensions as the original object, but
+with missing values replaced by the next non-missing value along the specified dimensions.
+
+.. ipython:: python
+
+    x = xr.DataArray([0, 1, np.nan, np.nan, 2], dims=["x"])
     x.bfill("x")
 
+In this example, there are two NaN values in 'x', so calling x.bfill("x") fills these values with the next
+non-null value in the same dimension, which are 2 and 2, respectively. The resulting :py:class:`~xarray.DataArray` object has
+five elements, containing the values [0, 1, 2, 2, 2] in the original order.
+
 Like pandas, xarray uses the float value ``np.nan`` (not-a-number) to represent
 missing values.
 
 Xarray objects also have an :py:meth:`~xarray.DataArray.interpolate_na` method
-for filling missing values via 1D interpolation.
+for filling missing values via 1D interpolation. It returns a new xarray object with the same dimensions
+as the original object, but with missing values interpolated.
 
 .. ipython:: python
 
@@ -100,6 +184,13 @@ for filling missing values via 1D interpolation.
     )
     x.interpolate_na(dim="x", method="linear", use_coordinate="xx")
 
+In this example, there are two NaN values in 'x', so calling x.interpolate_na(dim="x", method="linear",
+use_coordinate="xx") fills these values with interpolated values along the "x" dimension using linear
+interpolation based on the values of the xx coordinate. The resulting :py:class:`~xarray.DataArray` object has five elements,
+containing the values [0., 1., 1.05, 1.45, 2.] in the original order. Note that the interpolated values
+are calculated based on the values of the 'xx' coordinate, which has non-integer values, resulting in
+non-integer interpolated values.
+
 Note that xarray slightly diverges from the pandas ``interpolate`` syntax by
 providing the ``use_coordinate`` keyword which facilitates a clear specification
 of which values to use as the index in the interpolation.
diff --git a/doc/user-guide/io.rst b/doc/user-guide/io.rst
index cf2b0b4b..dc495b9f 100644
--- a/doc/user-guide/io.rst
+++ b/doc/user-guide/io.rst
@@ -608,6 +608,13 @@ store is already present at that path, an error will be raised, preventing it
 from being overwritten. To override this behavior and overwrite an existing
 store, add ``mode='w'`` when invoking :py:meth:`~Dataset.to_zarr`.
 
+DataArrays can also be saved to disk using the :py:meth:`DataArray.to_zarr` method,
+and loaded from disk using the :py:func:`open_dataarray` function with `engine='zarr'`.
+Similar to :py:meth:`DataArray.to_netcdf`, :py:meth:`DataArray.to_zarr` will
+convert the ``DataArray`` to a ``Dataset`` before saving, and then convert back
+when loading, ensuring that the ``DataArray`` that is loaded is always exactly
+the same as the one that was saved.
+
 .. note::
 
     xarray does not write NCZarr attributes. Therefore, NCZarr data must be
diff --git a/doc/whats-new.rst b/doc/whats-new.rst
index 681fb1f0..eedb8c71 100644
--- a/doc/whats-new.rst
+++ b/doc/whats-new.rst
@@ -25,9 +25,11 @@ New Features
 - New methods to reset an objects encoding (:py:meth:`Dataset.reset_encoding`, :py:meth:`DataArray.reset_encoding`).
   (:issue:`7686`, :pull:`7689`).
   By `Joe Hamman <https://github.com/jhamman>`_.
-
 - Allow refreshing backend engines with :py:meth:`xarray.backends.refresh_engines` (:issue:`7478`, :pull:`7523`).
   By `Michael Niklas <https://github.com/headtr1ck>`_.
+- Added ability to save ``DataArray`` objects directly to Zarr using :py:meth:`~xarray.DataArray.to_zarr`.
+  (:issue:`7692`, :pull:`7693`) .
+  By `Joe Hamman <https://github.com/jhamman>`_.
 
 Breaking changes
 ~~~~~~~~~~~~~~~~
@@ -72,6 +74,9 @@ Internal Changes
   backend interface, so no existing code should break.
   By `Deepak Cherian <https://github.com/dcherian>`_.
 
+- Added a config.yml file with messages for the welcome bot when a Github user creates their first ever issue or pull request or has their first PR merged. (:issue:`7685`, :pull:`7685`)
+  By `Nishtha P <https://github.com/nishthap981>`_.
+
 .. _whats-new.2023.03.0:
 
 v2023.03.0 (March 22, 2023)
diff --git a/xarray/core/dataarray.py b/xarray/core/dataarray.py
index ba55837e..d4eb5fae 100644
--- a/xarray/core/dataarray.py
+++ b/xarray/core/dataarray.py
@@ -2,7 +2,7 @@ from __future__ import annotations
 
 import datetime
 import warnings
-from collections.abc import Hashable, Iterable, Mapping, Sequence
+from collections.abc import Hashable, Iterable, Mapping, MutableMapping, Sequence
 from os import PathLike
 from typing import TYPE_CHECKING, Any, Callable, Literal, NoReturn, cast, overload
 
@@ -70,6 +70,7 @@ if TYPE_CHECKING:
     except ImportError:
         iris_Cube = None
 
+    from xarray.backends import ZarrStore
     from xarray.backends.api import T_NetcdfEngine, T_NetcdfTypes
     from xarray.core.groupby import DataArrayGroupBy
     from xarray.core.resample import DataArrayResample
@@ -3855,7 +3856,7 @@ class DataArray(
         compute: bool = True,
         invalid_netcdf: bool = False,
     ) -> bytes | Delayed | None:
-        """Write dataset contents to a netCDF file.
+        """Write DataArray contents to a netCDF file.
 
         Parameters
         ----------
@@ -3969,6 +3970,210 @@ class DataArray(
             invalid_netcdf=invalid_netcdf,
         )
 
+    # compute=True (default) returns ZarrStore
+    @overload
+    def to_zarr(
+        self,
+        store: MutableMapping | str | PathLike[str] | None = None,
+        chunk_store: MutableMapping | str | PathLike | None = None,
+        mode: Literal["w", "w-", "a", "r+", None] = None,
+        synchronizer=None,
+        group: str | None = None,
+        encoding: Mapping | None = None,
+        compute: Literal[True] = True,
+        consolidated: bool | None = None,
+        append_dim: Hashable | None = None,
+        region: Mapping[str, slice] | None = None,
+        safe_chunks: bool = True,
+        storage_options: dict[str, str] | None = None,
+        zarr_version: int | None = None,
+    ) -> ZarrStore:
+        ...
+
+    # compute=False returns dask.Delayed
+    @overload
+    def to_zarr(
+        self,
+        store: MutableMapping | str | PathLike[str] | None = None,
+        chunk_store: MutableMapping | str | PathLike | None = None,
+        mode: Literal["w", "w-", "a", "r+", None] = None,
+        synchronizer=None,
+        group: str | None = None,
+        encoding: Mapping | None = None,
+        *,
+        compute: Literal[False],
+        consolidated: bool | None = None,
+        append_dim: Hashable | None = None,
+        region: Mapping[str, slice] | None = None,
+        safe_chunks: bool = True,
+        storage_options: dict[str, str] | None = None,
+        zarr_version: int | None = None,
+    ) -> Delayed:
+        ...
+
+    def to_zarr(
+        self,
+        store: MutableMapping | str | PathLike[str] | None = None,
+        chunk_store: MutableMapping | str | PathLike | None = None,
+        mode: Literal["w", "w-", "a", "r+", None] = None,
+        synchronizer=None,
+        group: str | None = None,
+        encoding: Mapping | None = None,
+        compute: bool = True,
+        consolidated: bool | None = None,
+        append_dim: Hashable | None = None,
+        region: Mapping[str, slice] | None = None,
+        safe_chunks: bool = True,
+        storage_options: dict[str, str] | None = None,
+        zarr_version: int | None = None,
+    ) -> ZarrStore | Delayed:
+        """Write DataArray contents to a Zarr store
+
+        Zarr chunks are determined in the following way:
+
+        - From the ``chunks`` attribute in each variable's ``encoding``
+          (can be set via `DataArray.chunk`).
+        - If the variable is a Dask array, from the dask chunks
+        - If neither Dask chunks nor encoding chunks are present, chunks will
+          be determined automatically by Zarr
+        - If both Dask chunks and encoding chunks are present, encoding chunks
+          will be used, provided that there is a many-to-one relationship between
+          encoding chunks and dask chunks (i.e. Dask chunks are bigger than and
+          evenly divide encoding chunks); otherwise raise a ``ValueError``.
+          This restriction ensures that no synchronization / locks are required
+          when writing. To disable this restriction, use ``safe_chunks=False``.
+
+        Parameters
+        ----------
+        store : MutableMapping, str or path-like, optional
+            Store or path to directory in local or remote file system.
+        chunk_store : MutableMapping, str or path-like, optional
+            Store or path to directory in local or remote file system only for Zarr
+            array chunks. Requires zarr-python v2.4.0 or later.
+        mode : {"w", "w-", "a", "r+", None}, optional
+            Persistence mode: "w" means create (overwrite if exists);
+            "w-" means create (fail if exists);
+            "a" means override existing variables (create if does not exist);
+            "r+" means modify existing array *values* only (raise an error if
+            any metadata or shapes would change).
+            The default mode is "a" if ``append_dim`` is set. Otherwise, it is
+            "r+" if ``region`` is set and ``w-`` otherwise.
+        synchronizer : object, optional
+            Zarr array synchronizer.
+        group : str, optional
+            Group path. (a.k.a. `path` in zarr terminology.)
+        encoding : dict, optional
+            Nested dictionary with variable names as keys and dictionaries of
+            variable specific encodings as values, e.g.,
+            ``{"my_variable": {"dtype": "int16", "scale_factor": 0.1,}, ...}``
+        compute : bool, default: True
+            If True write array data immediately, otherwise return a
+            ``dask.delayed.Delayed`` object that can be computed to write
+            array data later. Metadata is always updated eagerly.
+        consolidated : bool, optional
+            If True, apply zarr's `consolidate_metadata` function to the store
+            after writing metadata and read existing stores with consolidated
+            metadata; if False, do not. The default (`consolidated=None`) means
+            write consolidated metadata and attempt to read consolidated
+            metadata for existing stores (falling back to non-consolidated).
+
+            When the experimental ``zarr_version=3``, ``consolidated`` must be
+            either be ``None`` or ``False``.
+        append_dim : hashable, optional
+            If set, the dimension along which the data will be appended. All
+            other dimensions on overridden variables must remain the same size.
+        region : dict, optional
+            Optional mapping from dimension names to integer slices along
+            dataarray dimensions to indicate the region of existing zarr array(s)
+            in which to write this datarray's data. For example,
+            ``{'x': slice(0, 1000), 'y': slice(10000, 11000)}`` would indicate
+            that values should be written to the region ``0:1000`` along ``x``
+            and ``10000:11000`` along ``y``.
+
+            Two restrictions apply to the use of ``region``:
+
+            - If ``region`` is set, _all_ variables in a dataarray must have at
+              least one dimension in common with the region. Other variables
+              should be written in a separate call to ``to_zarr()``.
+            - Dimensions cannot be included in both ``region`` and
+              ``append_dim`` at the same time. To create empty arrays to fill
+              in with ``region``, use a separate call to ``to_zarr()`` with
+              ``compute=False``. See "Appending to existing Zarr stores" in
+              the reference documentation for full details.
+        safe_chunks : bool, default: True
+            If True, only allow writes to when there is a many-to-one relationship
+            between Zarr chunks (specified in encoding) and Dask chunks.
+            Set False to override this restriction; however, data may become corrupted
+            if Zarr arrays are written in parallel. This option may be useful in combination
+            with ``compute=False`` to initialize a Zarr store from an existing
+            DataArray with arbitrary chunk structure.
+        storage_options : dict, optional
+            Any additional parameters for the storage backend (ignored for local
+            paths).
+        zarr_version : int or None, optional
+            The desired zarr spec version to target (currently 2 or 3). The
+            default of None will attempt to determine the zarr version from
+            ``store`` when possible, otherwise defaulting to 2.
+
+        Returns
+        -------
+            * ``dask.delayed.Delayed`` if compute is False
+            * ZarrStore otherwise
+
+        References
+        ----------
+        https://zarr.readthedocs.io/
+
+        Notes
+        -----
+        Zarr chunking behavior:
+            If chunks are found in the encoding argument or attribute
+            corresponding to any DataArray, those chunks are used.
+            If a DataArray is a dask array, it is written with those chunks.
+            If not other chunks are found, Zarr uses its own heuristics to
+            choose automatic chunk sizes.
+
+        encoding:
+            The encoding attribute (if exists) of the DataArray(s) will be
+            used. Override any existing encodings by providing the ``encoding`` kwarg.
+
+        See Also
+        --------
+        Dataset.to_zarr
+        :ref:`io.zarr`
+            The I/O user guide, with more details and examples.
+        """
+        from xarray.backends.api import DATAARRAY_NAME, DATAARRAY_VARIABLE, to_zarr
+
+        if self.name is None:
+            # If no name is set then use a generic xarray name
+            dataset = self.to_dataset(name=DATAARRAY_VARIABLE)
+        elif self.name in self.coords or self.name in self.dims:
+            # The name is the same as one of the coords names, which the netCDF data model
+            # does not support, so rename it but keep track of the old name
+            dataset = self.to_dataset(name=DATAARRAY_VARIABLE)
+            dataset.attrs[DATAARRAY_NAME] = self.name
+        else:
+            # No problems with the name - so we're fine!
+            dataset = self.to_dataset()
+
+        return to_zarr(  # type: ignore[call-overload,misc]
+            dataset,
+            store=store,
+            chunk_store=chunk_store,
+            mode=mode,
+            synchronizer=synchronizer,
+            group=group,
+            encoding=encoding,
+            compute=compute,
+            consolidated=consolidated,
+            append_dim=append_dim,
+            region=region,
+            safe_chunks=safe_chunks,
+            storage_options=storage_options,
+            zarr_version=zarr_version,
+        )
+
     def to_dict(self, data: bool = True, encoding: bool = False) -> dict[str, Any]:
         """
         Convert this xarray.DataArray into a dictionary following xarray
diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py
index d3a5ddd4..23c79a3e 100644
--- a/xarray/core/dataset.py
+++ b/xarray/core/dataset.py
@@ -1965,6 +1965,7 @@ class Dataset(
         region: Mapping[str, slice] | None = None,
         safe_chunks: bool = True,
         storage_options: dict[str, str] | None = None,
+        zarr_version: int | None = None,
     ) -> Delayed:
         ...
 
@@ -2023,7 +2024,7 @@ class Dataset(
             Nested dictionary with variable names as keys and dictionaries of
             variable specific encodings as values, e.g.,
             ``{"my_variable": {"dtype": "int16", "scale_factor": 0.1,}, ...}``
-        compute : bool, optional
+        compute : bool, default: True
             If True write array data immediately, otherwise return a
             ``dask.delayed.Delayed`` object that can be computed to write
             array data later. Metadata is always updated eagerly.
@@ -2057,7 +2058,7 @@ class Dataset(
               in with ``region``, use a separate call to ``to_zarr()`` with
               ``compute=False``. See "Appending to existing Zarr stores" in
               the reference documentation for full details.
-        safe_chunks : bool, optional
+        safe_chunks : bool, default: True
             If True, only allow writes to when there is a many-to-one relationship
             between Zarr chunks (specified in encoding) and Dask chunks.
             Set False to override this restriction; however, data may become corrupted
@@ -2101,7 +2102,7 @@ class Dataset(
         """
         from xarray.backends.api import to_zarr
 
-        return to_zarr(  # type: ignore
+        return to_zarr(  # type: ignore[call-overload,misc]
             self,
             store=store,
             chunk_store=chunk_store,


Test patch:
diff --git a/.github/workflows/testpypi-release.yaml b/.github/workflows/testpypi-release.yaml
index b892e972..65942721 100644
--- a/.github/workflows/testpypi-release.yaml
+++ b/.github/workflows/testpypi-release.yaml
@@ -78,7 +78,7 @@ jobs:
 
       - name: Publish package to TestPyPI
         if: github.event_name == 'push'
-        uses: pypa/gh-action-pypi-publish@v1.8.3
+        uses: pypa/gh-action-pypi-publish@v1.8.4
         with:
           user: __token__
           password: ${{ secrets.TESTPYPI_TOKEN }}
diff --git a/xarray/tests/test_backends.py b/xarray/tests/test_backends.py
index 2b1e7677..14b510d4 100644
--- a/xarray/tests/test_backends.py
+++ b/xarray/tests/test_backends.py
@@ -3237,6 +3237,21 @@ def chunks(request):
     return request.param
 
 
+@pytest.fixture(params=["tmp_path", "ZipStore", "Dict"])
+def tmp_store(request, tmp_path):
+    if request.param == "tmp_path":
+        return tmp_path
+    elif request.param == "ZipStore":
+        from zarr.storage import ZipStore
+
+        path = tmp_path / "store.zip"
+        return ZipStore(path)
+    elif request.param == "Dict":
+        return dict()
+    else:
+        raise ValueError("not supported")
+
+
 # using pytest.mark.skipif does not work so this a work around
 def skip_if_not_engine(engine):
     if engine == "netcdf4":
@@ -4591,6 +4606,56 @@ class TestDataArrayToNetCDF:
                 assert_identical(original_da, loaded_da)
 
 
+@requires_zarr
+class TestDataArrayToZarr:
+    def test_dataarray_to_zarr_no_name(self, tmp_store) -> None:
+        original_da = DataArray(np.arange(12).reshape((3, 4)))
+
+        original_da.to_zarr(tmp_store)
+
+        with open_dataarray(tmp_store, engine="zarr") as loaded_da:
+            assert_identical(original_da, loaded_da)
+
+    def test_dataarray_to_zarr_with_name(self, tmp_store) -> None:
+        original_da = DataArray(np.arange(12).reshape((3, 4)), name="test")
+
+        original_da.to_zarr(tmp_store)
+
+        with open_dataarray(tmp_store, engine="zarr") as loaded_da:
+            assert_identical(original_da, loaded_da)
+
+    def test_dataarray_to_zarr_coord_name_clash(self, tmp_store) -> None:
+        original_da = DataArray(
+            np.arange(12).reshape((3, 4)), dims=["x", "y"], name="x"
+        )
+
+        original_da.to_zarr(tmp_store)
+
+        with open_dataarray(tmp_store, engine="zarr") as loaded_da:
+            assert_identical(original_da, loaded_da)
+
+    def test_open_dataarray_options(self, tmp_store) -> None:
+        data = DataArray(np.arange(5), coords={"y": ("x", range(5))}, dims=["x"])
+
+        data.to_zarr(tmp_store)
+
+        expected = data.drop_vars("y")
+        with open_dataarray(tmp_store, engine="zarr", drop_variables=["y"]) as loaded:
+            assert_identical(expected, loaded)
+
+    @requires_dask
+    def test_dataarray_to_zarr_compute_false(self, tmp_store) -> None:
+        from dask.delayed import Delayed
+
+        original_da = DataArray(np.arange(12).reshape((3, 4)))
+
+        output = original_da.to_zarr(tmp_store, compute=False)
+        assert isinstance(output, Delayed)
+        output.compute()
+        with open_dataarray(tmp_store, engine="zarr") as loaded_da:
+            assert_identical(original_da, loaded_da)
+
+
 @requires_scipy_or_netCDF4
 def test_no_warning_from_dask_effective_get() -> None:
     with create_tmp_file() as tmpfile: