Customize the overall layout, header and footer of the page.
This is a special component that provides the page structure wrapping all other components on your page.
It generates the complete HTML document including the <head> section with metadata, title, and stylesheets,
as well as the navigation bar, main content area, and footer.
If you don't explicitly call the shell component at the top of your SQL file, SQLPage will automatically
add a default shell component before your first try to display data on the page.
Use the shell component to customize page-wide settings like the page title, navigation menu, theme, fonts,
and to include custom visual styles (with CSS) or interactive behavior (with JavaScript) that should be loaded on the page.
Top-level parameters
name
required
type
description
css
URL
The URL of a CSS file to load and apply to the page.
description
TEXT
A description of the page. It can be displayed by search engines when your page appears in their results.
favicon
URL
fixed_top_menu
BOOLEAN
Fixes the top bar with menu at the top (the top bar remains visible when scrolling long pages).
font
TEXT
Specifies the font to be used for displaying text, which can be a valid font name from fonts.google.com or the path to a local WOFF2 font file starting with a slash (e.g., "/fonts/MyLocalFont.woff2").
font_size
INTEGER
Font size on the page, in pixels. Set to 18 by default.
footer
TEXT
Muted text to display in the footer of the page. This can be used to display a link to the terms and conditions of your application, for instance. By default, shows "Built with SQLPage". Supports links with markdown.
Name of an icon (from tabler-icons.io) to display next to the title in the navigation bar.
image
URL
The URL of an image to display next to the page title.
javascript
URL
The URL of a Javascript file to load and execute on the page.
javascript_module
URL
The URL of a javascript module in the ESM format (see javascript.info/modules)
language
TEXT
The language of the page. This can be used by search engines and screen readers to determine in which language the page is written.
layout
TEXT
The general page layout. Can be "boxed" (the default), "horizontal" (for a full-width menu), "vertical"(vertical menu), "fluid" (removes side margins).
link
URL
The target of the link in the top navigation bar.
manifest
URL
menu_item
TEXT
Adds a menu item in the navigation bar at the top of the page. The menu item will have the specified name, and will link to as .sql file of the same name. A dropdown can be generated by passing a json object with a `title` and `submenu` properties.
navbar_title
TEXT
The title to display in the top navigation bar. Used to display a different title in the top menu than the one that appears in the tab of the browser.
norobot
BOOLEAN
Forbids robots to save this page in their database and follow the links on this page. This will prevent this page to appear in Google search results for any query, for instance.
preview_image
URL
The URL of an image to display as a link preview when the page is shared on social media
refresh
INTEGER
Number of seconds after which the page should refresh. This can be useful to display dynamic content that updates automatically.
rss
URL
The URL of an RSS feed to display in the top navigation bar. You can use the rss component to generate the field.
rtl
BOOLEAN
Whether the page should be displayed in right-to-left mode. Used to display Arabic, Hebrew, Persian, etc.
search_button
TEXT
Customizes the text displayed on the search button. Replaces the default "Search" label with custom text that may better match your applications terminology or language.
search_placeholder
TEXT
Customizes the placeholder text shown in the search input field. Replaces the default "Search" with text that better describes what users should search for.
search_target
TEXT
When this is set, a search field will appear in the top navigation bar, and load the specified sql file with an URL parameter named "search" when the user searches something.
search_value
TEXT
This value will be placed in the search field when "search_target" is set. Using the "$search" query parameter value will mirror the value that the user has searched for.
sidebar
BOOLEAN
Whether the menu defined by menu_item should be displayed on the left side of the page instead of the top. Introduced in v0.27.
sidebar_theme
BOOLEAN
Used with sidebar property, It can be set to "dark" to exclusively set the sidebar into dark theme.
social_image
URL
The URL of the preview image that will appear in the Open Graph metadata when the page is shared on social media.
target
TEXT
"_blank" to open the link in a new tab, "_self" to open it in the same tab, "_parent" to open it in the parent frame, or "_top" to open it in the full body of the window
theme
TEXT
Set to "dark" to use a dark theme.
title
TEXT
The title of your page. Will be shown in a top bar above the page contents. Also usually displayed by web browsers as the name of the web page's tab.
No data
Example 1
This example contains the values used for the shell of the page you are currently viewing.
The menu_item property is used both in its simple string form, to generate a link named "functions" that points to "functions.sql",
and in its object form, to generate a dropdown menu named "Community" with links to the blog, the github repository, and the issues page.
The object form can be used directly only on database engines that have a native JSON type.
On other engines (such as SQLite), you can use the dynamic component to generate the same result.
You see the page layouts demo for a live example of the different layouts.
select
'shell' as component,
'SQLPage: SQL websites' as title,
'database' as icon,
'/' as link,
JSON('{"title":"About","submenu":[{"link":"/safety.sql","title":"Security","icon":"lock"},{"link":"/performance.sql","title":"Performance","icon":"bolt"},{"link":"//github.com/sqlpage/SQLPage/blob/main/LICENSE.txt","title":"License","icon":"file-text"},{"link":"/blog.sql","title":"Articles","icon":"book"}]}') as menu_item,
JSON('{"title":"Examples","submenu":[{"link":"/examples/tabs/","title":"Tabs","icon":"layout-navbar"},{"link":"/examples/layouts.sql","title":"Layouts","icon":"layout"},{"link":"/examples/multistep-form","title":"Forms","icon":"edit"},{"link":"/examples/handle_picture_upload.sql","title":"File uploads","icon":"upload"},{"link":"/examples/authentication/","title":"Password protection","icon":"password-user"},{"link":"//github.com/sqlpage/SQLPage/blob/main/examples/","title":"All examples & demos","icon":"code"}]}') as menu_item,
JSON('{"title":"Community","submenu":[{"link":"/blog.sql","title":"Blog","icon":"book"},{"link":"//github.com/sqlpage/SQLPage/issues","title":"Report a bug","icon":"bug"},{"link":"//github.com/sqlpage/SQLPage/discussions","title":"Discussions","icon":"message"},{"link":"//github.com/sqlpage/SQLPage","title":"Github","icon":"brand-github"}]}') as menu_item,
JSON('{"title":"Documentation","submenu":[{"link":"/your-first-sql-website","title":"Getting started","icon":"book"},{"link":"/components.sql","title":"All Components","icon":"list-details"},{"link":"/functions.sql","title":"SQLPage Functions","icon":"math-function"},{"link":"/extensions-to-sql","title":"Extensions to SQL","icon":"cube-plus"},{"link":"/custom_components.sql","title":"Custom Components","icon":"puzzle"},{"link":"//github.com/sqlpage/SQLPage/blob/main/configuration.md#configuring-sqlpage","title":"Configuration","icon":"settings"}]}') as menu_item,
JSON('{"title":"Search","link":"/search"}') as menu_item,
'boxed' as layout,
'en-US' as language,
'Go from SQL queries to web applications in an instant.' as description,
'https://sql-page.com/sqlpage_social_preview.webp' as preview_image,
'dark' as theme,
'Poppins' as font,
'https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/highlight.min.js' as javascript,
'https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/languages/sql.min.js' as javascript,
'https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/languages/handlebars.min.js' as javascript,
'https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/languages/json.min.js' as javascript,
'/assets/highlightjs-launch.js' as javascript,
'/assets/highlightjs-and-tabler-theme.css' as css,
'[Built with SQLPage](https://github.com/sqlpage/SQLPage/tree/main/examples/official-site)' as footer;
Example 2
This example shows how to set menu items as active in the navigation, so that they are highlighted in the nav bar.
In this example you can see that two menu items are created, "Home" and "About" and the "Home" tab is marked as active.
select
'shell' as component,
'SQLPage: SQL websites' as title,
'database' as icon,
'/' as link,
JSON('{"title":"Home","active":true}') as menu_item,
JSON('{"title":"About"}') as menu_item;
Example 3
Returning custom HTML, XML, plain text, or other formats
Use shell-empty to opt out of SQLPage's component system and return raw data directly.
By default, SQLPage wraps all your content in a complete HTML page with navigation and styling.
The shell-empty component tells SQLPage to skip this HTML wrapper and return only the raw content you specify.
Use it to create endpoints that return things like
plain text or markdown content (for instance for consumption by LLMs)
a custom data format you need
When using shell-empty, you should use the http_header component first
to set the correct content type (like application/json or application/xml).
select
'http_header' as component,
'application/xml' as "Content-Type";
select
'shell-empty' as component,
'<?xml version="1.0"?>
<user>
<account>42</account>
<login>john.doe</login>
</user>' as contents;
Example 4
Generate your own HTML
If you generate your own HTML from a SQL query, you can also use the shell-empty component to include it in a page.
This is useful when you want to generate a snippet of HTML that can be dynamically included in a larger page.
Make sure you know what you are doing, and be careful to escape the HTML properly,
as you are stepping out of the safe SQLPage framework and into the wild world of HTML.
In this scenario, you can use the html property, which serves as an alias for the contents property.
This property improves code readability by clearly indicating that you are generating HTML.
Since SQLPage returns HTML by default, there is no need to specify the content type in the HTTP header.
select
'shell-empty' as component,
'<!DOCTYPE html>
<html>
<head>
<title>My page</title>
</head>
<body>
<h1>My page</h1>
</body>
</html>' as html;
Examples
Sharing the shell between multiple pages
It is common to want to share the same shell between multiple pages.
Static menu
If your menu is completely static (it does not depend on the database content),
you can use the dynamic component together with the
sqlpage.read_file_as_text function to load the shell from
a json file.
SELECT 'dynamic' AS component, sqlpage.read_file_as_text('shell.json') AS properties;
If your menu depends on the database content, or on special sqlpage functions,
you can use the dynamic component,
but this time with the sqlpage.run_sql
function to generate the menu from the database.
SELECT 'dynamic' AS component, sqlpage.run_sql('shell.sql') AS properties;
and in shell.sql:
SELECT 'shell' AS component, 'run_sql is cool' as title,
json_group_array(json_object(
'link', link,
'title', title
)) as menu_item
FROM my_menu_items
(check your database documentation for the exact syntax of the json_group_array function).
Another case when dynamic menus are useful is when you want to show some
menu items only in certain conditions.
For instance, you could show an "Admin panel" menu item only to users with the "admin" role,
a "Profile" menu item only to authenticated users,
and a "Login" menu item only to unauthenticated users:
set role = (
SELECT role FROM users
INNER JOIN sessions ON users.id = sessions.user_id
WHERE sessions.session_id = sqlpage.cookie('session_id')
); -- Read more about how to handle user sessions in the "authentication" component documentation
SELECT
'shell' AS component,
'My authenticated website' AS title,
-- Add an admin panel link if the user is an admin
CASE WHEN $role = 'admin' THEN '{"link": "admin.sql", "title": "Admin panel"}' END AS menu_item,
-- Add a profile page if the user is authenticated
CASE WHEN $role IS NOT NULL THEN '{"link": "profile.sql", "title": "My profile"}' END AS menu_item,
-- Add a login link if the user is not authenticated
CASE WHEN $role IS NULL THEN 'login' END AS menu_item
;
The "icon" attribute may be specified for items in the top menu and submenus to display an icon
before the title (or instead). Similarly, the "image" attribute defines a file-based icon. For
image-based icons, the "size" attribute may be specified at the top level of menu_item only to
reduce the size of image-based icons. The following snippet provides an example, which is also
available here.
SELECT
'shell' AS component,
'SQLPage' AS title,
'database' AS icon,
'/' AS link,
TRUE AS fixed_top_menu,
'{"title":"About","icon": "settings","submenu":[{"link":"/safety.sql","title":"Security","icon": "logout"},{"link":"/performance.sql","title":"Performance"}]}' AS menu_item,
'{"title":"Examples","image": "https://upload.wikimedia.org/wikipedia/en/6/6b/Terrestrial_globe.svg","submenu":[{"link":"/examples/tabs/","title":"Tabs","image": "https://upload.wikimedia.org/wikipedia/en/6/6b/Terrestrial_globe.svg"},{"link":"/examples/layouts.sql","title":"Layouts"}]}' AS menu_item,
'{"title":"Examples","size":"sm","image": "https://upload.wikimedia.org/wikipedia/en/6/6b/Terrestrial_globe.svg","submenu":[{"link":"/examples/tabs/","title":"Tabs","image": "https://upload.wikimedia.org/wikipedia/en/6/6b/Terrestrial_globe.svg"},{"link":"/examples/layouts.sql","title":"Layouts"}]}' AS menu_item,
'Official [SQLPage](https://sql-page.com) documentation' as footer;