Skip to content

Design System — UI Components / Composants UI

Update date : 2026-05-16 02:41

Status / Statut : ui_components/ is planned for L2. The API documented here is the target interface — implementations are pending. / ui_components/ est planifié pour L2. L'API documentée ici est l'interface cible — les implémentations sont en cours.

Reference for all UI components. / Référence pour tous les composants UI.


Import conventions / Conventions d'import

Always import with sks_ aliases to avoid shadowing st.* names. / Toujours importer avec des alias sks_ pour éviter d'écraser les noms st.*.

from pinky_streamlit import text    as sks_text
from pinky_streamlit import header  as sks_header
from pinky_streamlit import badge   as sks_badge
from pinky_streamlit import metric  as sks_metric
from pinky_streamlit import filters as sks_filters

Text elements / Éléments texte

header()ui_components/text/

Section heading with optional icon. / En-tête de section avec icône optionnelle.

Param Type Default Description
title str Header text / Texte du header
level int 2 Heading level 1–3 / Niveau de titre
icon str \| None None Material icon string / Chaîne Material icon
accent str "primary" Color token / Token de couleur
from pinky_streamlit import header as sks_header

sks_header("Buildings", icon=str(ICONS.BUILDING), accent="primary")
sks_header("Details", level=3, icon=str(ICONS.INFO), accent="grey")

text()ui_components/text/

Styled paragraph. / Paragraphe stylisé.

from pinky_streamlit import text as sks_text

sks_text("Step completed successfully", accent="success", size="sm")
sks_text("Note: all fields are required", accent="grey", muted=True)

badge()ui_components/text/

Colored pill label. / Label pill coloré.

from pinky_streamlit import badge as sks_badge

sks_badge("Completed", accent="success")
sks_badge("3 alerts", accent="warning")
sks_badge("Failed", accent="error")
sks_badge("In progress", accent="primary")

empty_state()ui_components/text/

Centered placeholder when a section has no data. / Placeholder centré quand une section n'a pas de données.

from pinky_streamlit import empty_state as sks_empty_state

sks_empty_state()
sks_empty_state("No files found", icon=str(ICONS.FOLDER))

Data elements / Éléments de données

metric()ui_components/data/

KPI card with value, label, and optional delta. / Carte KPI avec valeur, label et delta optionnel.

from pinky_streamlit import metric as sks_metric

sks_metric("Billed penalties", "24.3 K €", delta="+2.7 K €", accent="primary", icon=ICONS.MONEY.material)
sks_metric("Active alerts", "0", accent="success", icon=ICONS.NOTIFICATION.material)
sks_metric("Anomalies", "12", delta="-3", accent="error")

Delta shows (green) or (red) automatically based on sign. / Le delta affiche (vert) ou (rouge) automatiquement selon le signe.

detail()ui_components/data/

Single key-value row for record detail panels. / Ligne clé-valeur unique pour les panneaux de détail.

from pinky_streamlit import detail as sks_detail

sks_detail("Status", "Active", icon=ICONS.SUCCESS.material)
sks_detail("Created by", login)

data_editor()ui_components/data/

Opinionated st.data_editor wrapper with inline edit detection, modification highlight, and save/cancel flow. / Wrapper opinioné de st.data_editor avec détection d'édition inline, surlignage des modifications et flux sauvegarde/annulation.

from pinky_streamlit import data_editor as sks_data_editor

sks_data_editor(
    df=df,
    key="buildings_editor",
    columns={"CODE": st.column_config.TextColumn("Code"), "RATE": st.column_config.NumberColumn("Rate")},
    on_save=lambda changes: update_data(session=session, data=changes, key="ID", table=TABLE),
    accent="primary",
)

Internal flow / Flux interne : 1. Renders st.data_editor with columns and column_order 2. Detects changes via st.session_state[key]["edited_rows"] 3. If changes: shows a modification preview with highlight (#d0d0d0) 4. Save button → calls on_save(change_list)st.rerun()

Key points / Points clés : - edited_rows is a sparse dict — only modified cells are present. / edited_rows est un dict sparse — seules les cellules modifiées sont présentes. - After save: st.session_state[key] is deleted to reset the editor. / Après sauvegarde : st.session_state[key] est supprimé pour réinitialiser l'éditeur.


Input widgets / Widgets d'entrée

filters() + FilterConfigui_components/widgets/

Declarative filter configuration. / Configuration déclarative des filtres.

from pinky_streamlit import filters as sks_filters, FilterConfig

filter_results = sks_filters([
    FilterConfig(column="COMPANY",   label="Company",  widget="pills_multi"),
    FilterConfig(column="STATUS",    label="Status",   widget="segmented_control"),
    FilterConfig(column="DATE",      label="Period",   widget="date_range"),
    FilterConfig(column="IS_ACTIVE", label="Active only", widget="toggle", default=True),
], key="my-filters")

df_filtered = df[
    df["COMPANY"].isin(filter_results["COMPANY"]) &
    (df["IS_ACTIVE"] == filter_results["IS_ACTIVE"])
]

Available widgets / Widgets disponibles :

Widget Streamlit component Selection
pills st.pills single
pills_multi st.pills multi
segmented_control st.segmented_control multi
multiselect st.multiselect multi
selectbox st.selectbox single + "All"
toggle st.toggle boolean
checkbox st.checkbox boolean
date st.date_input single date
date_range st.date_input range
slider st.slider numeric or range
number_input st.number_input numeric

add_dialog() + FormFieldConfigui_components/widgets/

Declarative modal form for insert/create flows. / Formulaire modal déclaratif pour les flux d'insertion/création.

from pinky_streamlit import add_dialog as sks_add_dialog, FormFieldConfig

FORM_FIELDS = [
    FormFieldConfig(column="CODE",        label="Code (*)",        widget="text_input",  required=True,  max_chars=5,  col_index=0),
    FormFieldConfig(column="DESCRIPTION", label="Description (*)", widget="text_input",  required=True,                col_index=1),
    FormFieldConfig(column="RATE",        label="Rate (*)",        widget="number_input", required=True, min_value=0.0, max_value=100.0, default=59.0, col_index=2),
]

@st.dialog(" ", width="large")
def add():
    sks_add_dialog(
        title="Create building",
        fields=FORM_FIELDS,
        df_existing=df,
        unique_columns=["CODE"],
        on_save=lambda row: insert_data(session=session, data=[row], key="CODE", table=TABLE),
    )

add_dialog() handles: N-column layout, required field validation, uniqueness check, on_save callback. / Gère : layout N colonnes, validation des champs requis, vérification d'unicité, callback on_save.

The @st.dialog decorator and st.rerun() stay in the page (app-specific). / Le décorateur @st.dialog et st.rerun() restent dans la page (spécifiques à l'app).

action_grid() + ActionConfigui_components/widgets/

Horizontal row of action buttons (app-launcher style). / Rangée horizontale de boutons d'action (style lanceur d'apps).

from pinky_streamlit import action_grid as sks_action_grid, ActionConfig

sks_action_grid([
    ActionConfig(icon=str(ICONS.UPLOAD),   key="btn-upload",  help="Import files"),
    ActionConfig(icon=str(ICONS.PLAY),     key="btn-run",     help="Start processing"),
    ActionConfig(icon=str(ICONS.DOWNLOAD), key="btn-export",  disabled=True, help="Export unavailable"),
    ActionConfig(icon=str(ICONS.SETTINGS), key="btn-settings",hidden=True),
], num_cols=2, square=True)

Layout containers / Containers de mise en page

card_grid()ui_components/layouts/

Responsive N-column card grid. / Grille de cards responsive en N colonnes.

from pinky_streamlit import card_grid as sks_card_grid

def my_card(item, idx):
    st.markdown(f"**{item['title']}**")
    st.caption(item["description"])

sks_card_grid(items=my_list, num_cols=3, render_func=my_card, key_prefix="my-cards")

Empty cells at the end of the grid are filled with st.empty(). / Les cellules vides en fin de grille sont remplies par st.empty().

divider()ui_components/layouts/

Horizontal rule with optional centered label. / Ligne horizontale avec label centré optionnel.

from pinky_streamlit import divider as sks_divider

sks_divider()
sks_divider("Details", accent="primary")
sks_divider("2025", accent="grey")

Status elements / Éléments de statut

status_card() + StatusStepConfigui_components/status/

Card with pipeline step indicators. / Carte avec indicateurs d'étapes de pipeline.

from pinky_streamlit import status_card as sks_status_card, StatusStepConfig

steps = [
    StatusStepConfig(label="Import",  icon=ICONS.SUCCESS.emoji),
    StatusStepConfig(label="Control", icon=ICONS.WARNING.emoji),
    StatusStepConfig(label="Publish", icon=ICONS.CANCEL.emoji),
]
sks_status_card("2025/12", steps=steps, download_url="https://...", key="card-202512")

Combine with card_grid() to display a list of status cards. / Combiner avec card_grid() pour afficher une liste de cartes de statut.


Charts — Plotly toolkit / Charts Plotly

Charts use PALETTE colors and return a plotly.graph_objects.Figure. / Les charts utilisent les couleurs PALETTE et retournent un plotly.graph_objects.Figure.

from pinky_streamlit import donut_chart, bar_chart, line_chart, area_chart

fig = donut_chart(20.4, accent="error")
st.plotly_chart(fig, use_container_width=True)

fig = bar_chart(df, x="DATE_PERIOD", y="TOTAL", accent="primary")
st.plotly_chart(fig, use_container_width=True)

fig = line_chart(df, x="DATE_PERIOD", y=["RATE_1", "RATE_2"], accent=["error", "warning"])
st.plotly_chart(fig, use_container_width=True)

fig = area_chart(df, x="DATE_PERIOD", y=["CAT_A", "CAT_B"], accent=["primary", "secondary"], stacked=True)
st.plotly_chart(fig, use_container_width=True)

Common patterns / Patterns courants

Hide icon columns in dataframes / Masquer les colonnes icônes dans les dataframes

Columns produced by add_status_icons() (e.g. STATUS_ICON) should be hidden. Use column_order to control which columns are visible. / Les colonnes produites par add_status_icons() doivent être masquées. Utiliser column_order pour contrôler les colonnes visibles.

column_config = {
    "CODE": st.column_config.TextColumn("Code"),
    "RATE": st.column_config.NumberColumn("Rate"),
    "STATUS_ICON": st.column_config.TextColumn(""),  # shown as icon
}
column_order = ["STATUS_ICON", "CODE", "RATE"]  # STATUS_ICON_RAW, etc. are excluded

st.dataframe(df, column_config=column_config, column_order=column_order)

Reset file_uploader after upload / Réinitialiser le file_uploader après upload

if "uploader_key" not in st.session_state:
    st.session_state.uploader_key = 0

st.file_uploader("File", key=f"upload_{st.session_state.uploader_key}")

# After successful upload / Après upload réussi
st.session_state.uploader_key += 1

Multi-file validation / Validation multi-fichiers

Stop at the first blocking error. / Stopper dès la première erreur bloquante.

  1. Pass 1 — Name: regex on filename (type, period, extension) / Regex sur le nom de fichier
  2. Pass 2 — Consistency: all files share the same period / batch / Tous les fichiers partagent la même période / lot
  3. Pass 3 — Content: row-by-row validation (columns, format, lengths) / Validation ligne par ligne

Upload to stage / Upload vers stage

session.file.put_stream(
    input_stream=file_bytes,
    stage_location=f"@STAGE/{filename}",
    auto_compress=False,
    overwrite=True,
)

Checklist for UI components / Checklist pour les composants UI

In addition to DESIGN_SYSTEM.md / En complément de DESIGN_SYSTEM.md :

  1. Provide images in two variants ({name}-light.png / {name}-dark.png) in demo/assets/ / Fournir les images en deux variantes
  2. Configure filters with FilterConfig + sks_filters() / Configurer les filtres avec FilterConfig + sks_filters()
  3. Configure add forms with FormFieldConfig + sks_add_dialog() / Configurer les formulaires avec FormFieldConfig + sks_add_dialog()
  4. Use sks_data_editor() for inline editing with highlight / Utiliser sks_data_editor() pour l'édition inline avec surlignage
  5. Use sks_card_grid() / sks_action_grid() for grid layouts / Utiliser sks_card_grid() / sks_action_grid() pour les layouts en grille