Language and appearance
Configure each admin instance when you create it. The same options work in FastAPI and Litestar:
from quite_admin import Admin, Theme
admin = Admin(
auth=auth_backend,
secret_key=session_secret,
title="Store administration",
description="Products, customers and orders in one place.",
language="en",
logo="assets/logo.svg",
theme=Theme(
primary="#2563eb",
background="#f8fafc",
surface="#ffffff",
text="#0f172a",
muted="#64748b",
border="#e2e8f0",
danger="#dc2626",
on_primary="#ffffff",
on_danger="#ffffff",
),
)
All settings are optional. Defaults are title="Quite Admin", description="",
language="en" and a neutral charcoal theme with a vivid blue accent.
Language
Set language="en" for English or language="ru" for Russian. Other values raise ValueError.
The language applies to all built-in screens: sign-in, navigation, CRUD actions, empty states,
pagination, boolean labels, validation errors and standard library error messages.
Russian record, table and field counts use the appropriate plural forms.
The HTML lang attribute follows the selected language.
Language selection is application configuration. There is no browser-language detection,
per-user language preference or built-in language switcher.
Different admin instances can use different languages and themes in the same application.
Give them different session_cookie names when mounting multiple instances on the same host.
Model and field labels, help text, enum choices, custom adapter errors, custom-page text
and record values belong to your application. They are not translated automatically.
Use ModelOptions(label=...) and FieldOptions(label=..., help_text=...) to name your own fields.
Only known library messages are translated; unknown error messages are displayed as supplied.
Submitted boolean values remain true / false, and stored data, URLs and log event names do not change.
The interface calls registered models tables in both languages: navigation, Home,
history filters and schema links use the same wording. To browse records, choose
Table list on Home or use Find a table. Existing custom templates can continue
using message IDs such as t('Collections'), t('Open collection') and
tn('collection', 'collections', count); they render the current table wording.
Python identifiers such as Admin.configure(collection, ...), history fields and filter
parameters named collection, and /models/<slug>/ URLs remain compatible.
Name and description
title is the admin name in the browser title and the main heading on Home and
the sign-in page. On other authenticated pages, the admin logo and title appear
on the right of the header; the breadcrumbs begin with the text Home.
The profile menu shows the library version.
description is plain text below the sign-in title and the Home heading. It is also
used in the HTML description metadata. An empty description omits that meta tag
and the description below the Home title. Both settings are escaped as text.
Set logo to an existing local SVG, PNG, JPEG, WebP or GIF file. Relative paths are resolved
against the application's working directory. It is served from the admin's /logo route,
including mount/proxy prefixes, and appears beside the Home title, on the sign-in page,
and beside the admin title on the right of other authenticated page headers.
It defaults to the bundled blue q mark, also used as the favicon. Missing files and unsupported extensions raise ValueError.
Custom templates receive logo_url; no external image hosts or CSP changes are required.
Colors
Theme accepts hexadecimal #RGB or #RRGGBB colors, case-insensitively.
Invalid colors raise ValueError when constructing the theme.
The default theme uses a neutral charcoal palette with vivid blue accents by default. The interface
retains its compact controls and sign-in card, with the logo beside the title. The GitHub social preview
is a separate repository asset and is not displayed on the sign-in page.
| Option | Default | Used for |
|---|---|---|
primary |
#3395fd |
Primary actions, selected navigation and active search/sort indicators |
background |
#181818 |
Main page background |
surface |
#202020 |
Icon rail, header, cards, inputs and panels |
text |
#fefefe |
Main text |
muted |
#b7b2bf |
Secondary text and hints |
border |
#3b3b45 |
Separators and borders |
danger |
#ff8798 |
Delete actions and error messages |
on_primary |
#111111 |
Text on primary buttons |
on_danger |
#111111 |
Text on destructive buttons |
Hover colors and tinted backgrounds are derived from the palette. Choose readable text/background
combinations, including on_primary and on_danger. For a dark palette:
theme = Theme(
primary="#93c5fd",
background="#0f172a",
surface="#172033",
text="#e2e8f0",
muted="#94a3b8",
border="#334155",
danger="#fca5a5",
on_primary="#0f172a",
on_danger="#450a0a",
)
The theme is served from the admin's own /theme.css route and loaded after the base stylesheet.
Mount paths and reverse-proxy prefixes are included automatically.
No inline styles, external CDN or JavaScript are required; the existing style-src 'self' policy stays in place.
Shared interface system
Built-in screens share the same compact typography, spacing tokens and components.
The system font stack is retained; no font download is required. Corners use 4 px badges,
6 px controls and 8 px panels. Surfaces sit close to the page background, separated by
1 px borders. Popovers use a dark shadow to separate them from the page.
List row height follows the density tokens, with right-aligned numeric columns and tabular numerals. The current sort
has a directional arrow and aria-sort; a newly selected column sorts ascending first.
The toolbar sits above the table frame, and the record count sits beside the page title.
The SVG star beside the table title and the stars in global table search share
the pinned state shown on Home. The × control in recent tables removes only that
recent entry; opening the table again restores it. See the interface tour
for browser-local limits and navigation.
An active search is shown below the toolbar. Clearing it resets the page and preserves
sorting and page size. Rows retain keyboard-accessible record links and a separate delete
confirmation link. Hover and keyboard focus identify the current row. Page-local selection
uses checkboxes; the compact right-hand icon opens bulk actions.
Boolean values use neutral text: true/false does not imply success/failure.
The accent identifies actions and selection; red identifies destructive actions and errors.
Record forms group writable fields, structured JSON data, read-only values and relationships
into sections within one surface. The footer keeps save/cancel actions visible while scrolling.
Built-in controls link their hints and validation errors with aria-describedby and mark invalid
fields with aria-invalid. Custom field templates should follow the same pattern. Custom record
actions appear in a separate Actions section. On small screens, forms use a single column,
the icon rail stays narrow and tables retain horizontal scrolling for comparison.
Use the tokens in your own same-origin stylesheet when extending the interface:
| Tokens | Purpose |
|---|---|
--text-xs, --text-sm, --text-base, --text-section, --text-title |
Typography scale |
--space-1 … --space-6, --space-8, --space-10 |
3, 6, 10, 13, 16, 19, 26 and 32 px spacing |
--radius-sm, --radius-control, --radius |
Badge, control and surface corners |
--bg, --paper, --subtle, --hover |
Page, surface, inset and row interaction levels |
--line, --border, --control-height |
Borders and shared 31 px control height |
Existing custom templates that extend the base template inherit the palette and shared styles.
To use the grouped form layout, wrap each .form-grid in a .form-section with a labelled
section heading. .record-form supplies the outer surface spacing; .form-footer supplies
the sticky action area. Template overrides can be compared with the built-in form.html.
Custom templates
Templates extending quite_admin/base.html inherit the configured name, language and colors.
The shared context includes title, description, language, theme, t and tn:
{% extends "quite_admin/base.html" %}
{% block content %}
<h1>{{ 'Отчёты' if language == 'ru' else 'Reports' }}</h1>
<p>{{ t('Save changes') }}</p>
<p>{{ total }} {{ tn('record', 'records', total) }}</p>
{% endblock %}
t(message, **values) and tn(singular, plural, count) use the built-in message catalog.
Custom copy needs your application's translations, as shown in the heading above.
In Python, the same helpers are available as admin.gettext(...) and admin.ngettext(...).
Use var(--accent), var(--paper), var(--text), var(--muted), var(--line) and
var(--danger) in your own same-origin stylesheets to follow the selected palette.
See custom pages and templates for template registration.
For a complete CSS loading recipe, density examples and template boundaries, see
Customize the interface.