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.