Data Access
This page covers how templates and partials read Eleventy data (global data, page data, and the built-in page object). The preset ships an eleventy singleton so you never have to prop-drill values from layouts down to partials.
The eleventy singleton
Import the singleton from @tuqulore-inc/eleventy-preset/eleventy. It is only valid inside JSX / MDX evaluated during SSR.
import { eleventy } from "@tuqulore-inc/eleventy-preset/eleventy";
<title>
{eleventy.title} | {eleventy.site.name}
</title>;
Partials work the same way — they import eleventy themselves rather than relying on props from the surrounding layout.
import { eleventy } from "@tuqulore-inc/eleventy-preset/eleventy";
<footer>
<p>© {eleventy.site.author}</p>
</footer>;
What is on the singleton
| Property | Description |
|---|---|
eleventy.content | Rendered HTML of the child template |
| Values from the current page's frontmatter |
| Top-level keys of the global data under |
eleventy.page | Eleventy's
(URL, date, and so on) |
eleventy.locale | The |
eleventy.collections | Eleventy collections. Front matter of an entry sits under |
eleventy.content is where a parent layout receives its child's rendered HTML. The value is already an HTML string, so embed it via dangerouslySetInnerHTML. Injecting it into the JSX tree directly would re-parse the child's output on top of the parent render, paying the cost twice.
Writing global data
Files under src/_data/ become top-level keys on the singleton.
// src/_data/site.js
export default {
name: "My Website",
description: "About this site",
url: process.env.SITE_URL,
author: "tuqulore inc.",
};
// From a template
<title>{eleventy.site.name}</title>
Sub-directories become nested keys:
src/_data/nav/ja.json
src/_data/nav/en.json
{
eleventy.nav.ja.map((item) => <a href={item.path}>{item.name}</a>);
}
{
eleventy.nav.en.map((item) => <a href={item.path}>{item.name}</a>);
}
Templates typically pick which side to read based on the current page's locale: eleventy.nav[eleventy.locale]. This is exactly what this documentation's sidebar does.
Typing the data
The preset ships type definitions for the eleventy singleton.
Eleventy's built-in data such as page, and common front matter fields such as title and description, are typed without any setup.
Types for global data and project-specific front matter are added per project through TypeScript declaration merging.
Add a type definition file and declare the shape of your data on the EleventyUserData interface.
import type nav from "./src/_data/nav.json";
import type site from "./src/_data/site.js";
declare module "@tuqulore-inc/eleventy-preset/eleventy" {
interface EleventyUserData {
site: typeof site;
nav: typeof nav;
ogp?: string;
}
}
With this, eleventy.site.name resolves to string, and a typo such as eleventy.site.nmae becomes a type error.
The types of site and nav are derived from the data files, so they follow edits to those files.
Target the module your templates import eleventy from (@tuqulore-inc/eleventy-preset/eleventy when going through the preset).
Do not target the plugin module the preset uses internally: a project installed with pnpm cannot resolve it, so declare module declares a new module instead of extending the types, and eleventy loses its type.
For the same reason, keep at least one top-level import in the type definition file. A file with neither import nor export is not treated as a module.
The default template ships this type definition file out of the box.
Collection entry types can be derived from schemas instead of hand-written declaration merging.
Placing a _schema.ts in a collection directory lets @tuqulore-inc/eleventy-collections, which the preset bundles, derive both build-time validation and the type of eleventy.collections.<name> from that schema.
The file name _schema.ts is reserved for this purpose.
See eleventy-collections for details.
Only valid during SSR
The eleventy singleton is only valid during SSR. Islands hydrated on the client cannot see it. To pass SSR-side values into an Island, hand them in as props on <Island>.
import { Island } from "@tuqulore-inc/eleventy-preset/island";
import Nav from "./nav.client.jsx";
<Island component={Nav} on="interaction" items={eleventy.nav.ja} />;
Props passed to <Island> flow to both the SSR render and the client-side hydration. What the browser sees after hydration matches what SSR rendered.
Reading SSR-only data inside an Island
Importing eleventy inside a .client.jsx file fails on the client — the import itself does not resolve. The rule is: SSR-only values always come in through <Island> props.
State that lives entirely inside the Island (user input, fetch results) is held with the component's own useState / useEffect. Anything that originated on the server side arrives as a prop.