diff --git a/gi-gtk-declarative.cabal b/gi-gtk-declarative.cabal
--- a/gi-gtk-declarative.cabal
+++ b/gi-gtk-declarative.cabal
@@ -1,5 +1,5 @@
 name:                 gi-gtk-declarative
-version:              0.6.1
+version:              0.6.2
 synopsis:             Declarative GTK+ programming in Haskell
 description:          A declarative programming model for GTK+ user
                       interfaces, implementing support for various widgets
@@ -42,6 +42,7 @@
                       , GI.Gtk.Declarative.Container.Class
                       , GI.Gtk.Declarative.Container.ListBox
                       , GI.Gtk.Declarative.Container.MenuItem
+                      , GI.Gtk.Declarative.Container.Notebook
                       , GI.Gtk.Declarative.Container.Paned
                       , GI.Gtk.Declarative.Container.Patch
                       , GI.Gtk.Declarative.EventSource
diff --git a/src/GI/Gtk/Declarative.hs b/src/GI/Gtk/Declarative.hs
--- a/src/GI/Gtk/Declarative.hs
+++ b/src/GI/Gtk/Declarative.hs
@@ -17,6 +17,7 @@
 import           GI.Gtk.Declarative.Container.ListBox  as Export ()
 import           GI.Gtk.Declarative.Container.MenuItem as Export
 import           GI.Gtk.Declarative.Container.Paned    as Export
+import           GI.Gtk.Declarative.Container.Notebook as Export
 import           GI.Gtk.Declarative.CustomWidget       as Export
 import           GI.Gtk.Declarative.Patch              as Export
 import           GI.Gtk.Declarative.SingleWidget       as Export
diff --git a/src/GI/Gtk/Declarative/Container/Notebook.hs b/src/GI/Gtk/Declarative/Container/Notebook.hs
new file mode 100644
--- /dev/null
+++ b/src/GI/Gtk/Declarative/Container/Notebook.hs
@@ -0,0 +1,91 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE OverloadedLabels      #-}
+{-# LANGUAGE OverloadedLists       #-}
+{-# LANGUAGE OverloadedStrings     #-}
+{-# LANGUAGE RecordWildCards       #-}
+
+-- | Implementation of 'Gtk.Notebook' as a declarative container.
+module GI.Gtk.Declarative.Container.Notebook
+  ( Page
+  , page
+  , pageWithTab
+  , notebook
+  ) where
+
+import           Control.Monad                      (void)
+import           Data.Maybe                         (isNothing)
+import           Data.Text                          (Text, pack)
+import           Data.Vector                        (Vector)
+import           GHC.Ptr                            (nullPtr)
+import qualified GI.GLib                            as GLib
+import qualified GI.Gtk                             as Gtk
+import           GI.Gtk.Declarative.Attributes
+import           GI.Gtk.Declarative.Container
+import           GI.Gtk.Declarative.Container.Class
+import           GI.Gtk.Declarative.SingleWidget
+import           GI.Gtk.Declarative.Widget
+
+-- | Describes a page to be added to a 'Notebook'
+data Page event =
+  Page
+    { tabLabel :: Widget event
+    , child    :: Widget event
+    }
+
+-- | Create a page with a textual label and an arbitrary content widget.
+page :: Text -> Widget event -> Page event
+page label = pageWithTab (widget Gtk.Label [#label := label])
+
+-- | Create a page with arbitrary widgets for both label and content.
+pageWithTab :: Widget event -> Widget event -> Page event
+pageWithTab = Page
+
+-- | Create a 'Notebook' by combining multiple pages.
+notebook ::
+     Vector (Attribute Gtk.Notebook event)
+  -> Vector (Page event)
+  -> Widget event
+notebook attrs children =
+  let childrenAndTabs = children >>= (\Page {..} -> [child, tabLabel])
+   in container Gtk.Notebook attrs childrenAndTabs
+
+instance ToChildren Gtk.Notebook Vector Widget
+
+instance IsContainer Gtk.Notebook Widget where
+  appendChild parent _ new = do
+    lastPage <- Gtk.notebookGetNthPage parent (-1)
+    case lastPage of
+      Nothing
+        -- this is the first page to be added
+       -> do
+        void $ Gtk.notebookAppendPage parent new (Nothing :: Maybe Gtk.Widget)
+      Just p -> do
+        label <- Gtk.notebookGetTabLabel parent p
+        if isNothing label
+            -- this page must already have a child, we just need to set the label
+          then do
+            Gtk.notebookSetTabLabel parent p (Just new)
+          else do
+            void $
+              Gtk.notebookAppendPage parent new (Nothing :: Maybe Gtk.Widget)
+  replaceChild parent _ i old new = do
+    let i' = i `div` 2
+    pageI <- Gtk.notebookGetNthPage parent i'
+    case pageI of
+      Nothing -> do
+        GLib.logDefaultHandler
+          (Just "gi-gtk-declarative")
+          [GLib.LogLevelFlagsLevelError]
+          (Just $
+           "GI.Gtk.Declarative.Container.Notebook.replaceChild called with an index where there is no child: " <>
+           pack (show i))
+          nullPtr
+      Just p -> do
+        if i `mod` 2 == 0
+          then do
+            label <- Gtk.notebookGetTabLabel parent p -- we have to replace the child
+            Gtk.widgetDestroy old
+            void $ Gtk.notebookInsertPage parent new label i'
+          else do
+            Gtk.notebookSetTabLabel parent p (Just new) -- we have to replace the label
