diff --git a/internal/api/ui_search.tmpl b/internal/api/ui_search.tmpl
new file mode 100644
index 0000000..76eceb0
--- /dev/null
+++ b/internal/api/ui_search.tmpl
@@ -0,0 +1,121 @@
+{{define "search"}}
+
+
+{{template "head" .}}
+
+ {{template "topbar" .}}
+ {{template "breadcrumbs" .}}
+
+
+
+ Global Search
+ {{if not .HasQuery}}
+ Enter a query in the search box above. Search covers assets, components, and failure events.
+ {{else}}
+ Query: {{.Query}} · Total matches: {{.TotalMatches}}
+ {{end}}
+
+
+ {{if .HasQuery}}
+
+ Assets
+ {{if .Assets}}
+
+
+
+ | Status |
+ Name |
+ Vendor Serial |
+ Vendor |
+ Model |
+ ID |
+
+
+
+ {{range .Assets}}
+
+ | {{assetStatusText (index $.AssetStatusByID .ID)}} |
+ {{.Name}} |
+ {{.VendorSerial}} |
+ {{if .Vendor}}{{.Vendor}}{{else}}—{{end}} |
+ {{if .Model}}{{.Model}}{{else}}—{{end}} |
+ {{.ID}} |
+
+ {{end}}
+
+
+ {{template "pagination" .AssetsPager}}
+ {{else}}
+ No asset matches.
+ {{end}}
+
+
+
+ Components
+ {{if .Components}}
+
+
+
+ | Status |
+ Vendor Serial |
+ Vendor |
+ Model |
+ Asset |
+ ID |
+
+
+
+ {{range .Components}}
+
+ | {{componentStatusText (index $.ComponentStatusByID .ID)}} |
+ {{.VendorSerial}} |
+ {{if .Vendor}}{{.Vendor}}{{else}}—{{end}} |
+ {{if .Model}}{{.Model}}{{else}}—{{end}} |
+ {{$asset := index $.ComponentAssetByID .ID}}
+ {{if $asset.ID}}{{$asset.Label}}{{else}}—{{end}} |
+ {{.ID}} |
+
+ {{end}}
+
+
+ {{template "pagination" .ComponentsPager}}
+ {{else}}
+ No component matches.
+ {{end}}
+
+
+
+ Failure Events
+ {{if .Failures}}
+
+ {{template "pagination" .FailuresPager}}
+ {{else}}
+ No failure matches.
+ {{end}}
+
+ {{end}}
+
+
+
+{{end}}