Skip to main content
st-rsuite logo

st-rsuite

Built using RSuite · Streamlit Components v2

PyPI version Python >=3.10 Streamlit >=1.51 Tests Open in Streamlit


Components

Pickers: rich popups with full interaction

Calendar popups, scrolling time panels, range selection with hover highlighting. Everything you'd expect from a production date/time picker. Popups stay anchored to their field while the Streamlit page scrolls, flip above the field when there is no room below but there is above, and hide once the field scrolls out of view.

Component Description Streamlit equivalent
date_picker Calendar popup with format control, one-tap, ISO week, datetime mode st.date_input
date_range_picker Dual-calendar popup for date ranges, hover range, datetime mode st.date_input (range mode)
time_picker Time picker with scrolling panel, AM/PM st.time_input
time_range_picker Time range picker with dual panels --

Inputs: simple keyboard-only entry

Lightweight alternatives with no popup. Users navigate date segments with arrow keys and typing.

Component Description Streamlit equivalent
date_input Keyboard-only date input (no popup) st.date_input
date_range_input Keyboard-only date range input (no popup) st.date_input (range mode)

Selection

Component Description Streamlit equivalent
radio_tile Tile-based radio group with icons and descriptions st.radio
select_picker Searchable single-select dropdown with grouping, virtualization, disabled options st.selectbox
tag_picker Searchable multi-select as removable tags; can create new options st.multiselect
check_picker Searchable multi-select dropdown with checkboxes, selected labels, and a count badge st.multiselect

Tree: hierarchical data selection

Component Description Streamlit equivalent
check_tree Standalone tree with checkboxes, searchable --
check_tree_picker Dropdown picker with checkbox tree inside st.multiselect (flat)
tree_picker Dropdown picker with single-select tree inside st.selectbox (flat)
cascader Single-select cascading column navigation --
multi_cascade_tree Multi-select cascading column navigation --

Display & Input

Component Description Streamlit equivalent
carousel Content/image carousel with autoplay, explicit local paths & URLs --
timeline Timeline with custom react-icons --
pin_input PIN/verification code input with masking st.text_input

All components are MIT licensed (RSuite is fully open-source).

Requirements

  • Streamlit >= 1.51: these components are built on Streamlit Components v2; 1.51 is the first release with the st.components.v2 API they rely on. st-rsuite works on every release from 1.51 onward (on 1.51 and 1.52 a small compatibility shim applies isolate_styles on the per-call renderer; from 1.53 it is applied at registration). On older Streamlit the components cannot register and you get a must be declared ... with asset_dir error (see Troubleshooting).
  • Python >= 3.10

Installation

uv add st-rsuite

or with pip:

pip install st-rsuite

Quick start

import streamlit as st
from datetime import date, time, timedelta
from st_rsuite import (
    date_picker, date_range_picker, time_picker,
    time_range_picker, date_input, date_range_input,
    radio_tile, check_tree, check_tree_picker,
    multi_cascade_tree, carousel, timeline, pin_input,
)

# ── Pickers ───────────────────────────────────────────────────────────────────

d = date_picker(label="Pick a date", value=date.today(), one_tap=True, key="my_dp")

start, end = date_range_picker(
    label="Trip dates",
    value=(date.today(), date.today() + timedelta(days=7)),
    hover_range="week",
    key="my_drp",
)

t = time_picker(
    label="Pick a time", value=time(9, 30),
    format="hh:mm aa", show_meridiem=True, key="my_tp",
)

t_start, t_end = time_range_picker(
    label="Shift hours",
    value=(time(9, 0), time(17, 0)),
    key="my_trp",
)

# ── Inputs ────────────────────────────────────────────────────────────────────

d2 = date_input(label="Type a date", value=date.today(), key="my_di")

start, end = date_range_input(
    label="Date range",
    value=(date.today(), date.today() + timedelta(days=7)),
    key="my_dri",
)

# ── Selection ─────────────────────────────────────────────────────────────────

selected = radio_tile(
    options=[
        # "icon" is rendered as text, so any short string works (emoji included)
        {"value": "a", "label": "Option A", "description": "First option", "icon": "A"},
        {"value": "b", "label": "Option B", "description": "Second option", "icon": "B"},
    ],
    value="a",
    inline=True,
    key="my_tile",
)

# ── Tree components ───────────────────────────────────────────────────────────

tree_data = [
    {"value": "frontend", "label": "Frontend", "children": [
        {"value": "react", "label": "React"},
        {"value": "vue", "label": "Vue"},
    ]},
    {"value": "backend", "label": "Backend", "children": [
        {"value": "python", "label": "Python"},
        {"value": "go", "label": "Go"},
    ]},
]

checked = check_tree(data=tree_data, searchable=True, default_expand_all=True, key="my_ct")

picked = check_tree_picker(
    data=tree_data, placeholder="Select items", key="my_ctp",
)

cascade_data = [
    {"value": "us", "label": "US", "children": [
        {"value": "ca", "label": "California", "children": [
            {"value": "sf", "label": "San Francisco"},
        ]},
    ]},
]

cascade_selected = multi_cascade_tree(data=cascade_data, key="my_mct")

# ── Carousel ──────────────────────────────────────────────────────────────────

active = carousel(
    items=[
        {"content": "Slide 1", "background": "#7c3aed"},
        {"content": "Slide 2", "background": "#6d28d9"},
    ],
    autoplay=True,
    key="my_carousel",
)

# ── Timeline ──────────────────────────────────────────────────────────────────

timeline(
    items=[
        {"content": "Order placed", "time": "10:00", "icon": "FaCreditCard", "color": "#7c3aed"},
        {"content": "Shipped", "time": "14:30", "icon": "FaTruck", "color": "#0891b2"},
        {"content": "Delivered", "time": "11:30", "icon": "FaCheck", "color": "#059669"},
    ],
    align="left",
    key="my_timeline",
)

# ── PinInput ──────────────────────────────────────────────────────────────────

code = pin_input(length=6, mask=False, otp=True, key="my_pin")

API

Pickers

date_picker

date_picker(
    label="",
    value=None,           # date object or YYYY-MM-DD string
    format="yyyy-MM-dd",
    appearance="default",  # 'default' | 'subtle'
    size="md",
    placeholder="",
    placement="bottomStart",
    one_tap=False,        # single-click select (no OK button)
    disabled=False,
    cleanable=True,
    block=False,          # full width
    iso_week=False,       # Monday-start weeks
    show_week_numbers=False,
    editable=True,        # allow keyboard entry (False = toggle-only)
    loading=False,        # show a loading indicator
    min_date=None,        # earliest selectable date (inclusive)
    max_date=None,        # latest selectable date (inclusive)
    disabled_dates=None,  # list of individual dates to disable
    disabled_weekdays=None,  # list of ints, 0=Monday .. 6=Sunday
    limit_start_year=None,   # lower year bound in the calendar
    limit_end_year=None,     # upper year bound in the calendar
    calendar_default_date=None,  # month the calendar opens on
    help=None,            # tooltip next to the label
    locale=None,          # e.g. 'ja_JP', 'zh_CN', 'es_ES'
    on_change=None,
    key=None,
    show_meridiem=False,  # 12-hour clock with AM/PM in the time panel
) -> date | datetime | None

Datetime mode: when format carries a time field, RSuite adds a time panel and the picker returns a datetime instead of a date. A format counts as a time format when it contains any of H h m s anywhere, quoted literals included (RSuite's own rule; M is month and d is day, so those do not count). value accepts a datetime, a date (time defaults to 00:00:00), or an ISO string of either shape.

from datetime import datetime

when = date_picker(
    label="Starts at",
    value=datetime(2026, 6, 1, 9, 30),
    format="yyyy-MM-dd HH:mm",
    key="dp_datetime",
)  # -> datetime.datetime(2026, 6, 1, 9, 30)

date_range_picker

date_range_picker(
    label="",
    value=None,           # tuple of (date, date)
    format="yyyy-MM-dd",
    character=" ~ ",
    appearance="default",
    size="md",
    placeholder="",
    placement="bottomStart",
    disabled=False,
    cleanable=True,
    block=False,
    iso_week=False,
    show_week_numbers=False,
    show_one_calendar=False,  # single calendar panel
    one_tap=False,
    hover_range=None,     # 'week' | 'month' | None
    editable=True,        # allow keyboard entry (False = toggle-only)
    loading=False,        # show a loading indicator
    min_date=None,        # earliest selectable date (inclusive)
    max_date=None,        # latest selectable date (inclusive)
    disabled_dates=None,  # list of individual dates to disable
    disabled_weekdays=None,  # list of ints, 0=Monday .. 6=Sunday
    limit_start_year=None,
    limit_end_year=None,
    ranges=None,          # shortcut presets; [] removes RSuite defaults
    default_calendar_value=None,  # (start, end) month the panels open on
    help=None,            # tooltip next to the label
    locale=None,
    on_change=None,
    key=None,
    show_meridiem=False,  # 12-hour clock with AM/PM in the time panel
) -> tuple[date | None, date | None] | tuple[datetime | None, datetime | None]

Datetime mode: the same rule applies here, and a time format turns this into a full date-time range picker returning two datetime values. Pair a 12-hour format such as "yyyy-MM-dd hh:mm aa" with show_meridiem=True for an AM/PM clock.

from datetime import datetime

start, end = date_range_picker(
    label="Shift window",
    value=(datetime(2026, 6, 1, 8, 0), datetime(2026, 6, 1, 17, 0)),
    format="yyyy-MM-dd HH:mm",
    key="drp_datetime",
)  # -> (datetime(2026, 6, 1, 8, 0), datetime(2026, 6, 1, 17, 0))

time_picker

time_picker(
    label="",
    value=None,           # time object or HH:MM string
    format="HH:mm",       # 'HH:mm', 'HH:mm:ss', 'hh:mm aa'
    appearance="default",
    size="md",
    placeholder="",
    placement="bottomStart",
    disabled=False,
    cleanable=True,
    block=False,
    show_meridiem=False,  # AM/PM toggle
    editable=True,        # allow keyboard entry (False = toggle-only)
    loading=False,        # show a loading indicator
    min_hour=None,        # earliest selectable hour, 0-23 (hides earlier)
    max_hour=None,        # latest selectable hour, 0-23 (hides later)
    hidden_hours=None,    # list of hours 0-23 to hide
    hidden_minutes=None,  # list of minutes 0-59 to hide
    hidden_seconds=None,  # list of seconds 0-59 to hide
    help=None,            # tooltip next to the label
    locale=None,
    on_change=None,
    key=None,
) -> time | None

time_range_picker

time_range_picker(
    label="",
    value=None,           # tuple of (time, time)
    format="HH:mm",
    character=" ~ ",
    appearance="default",
    size="md",
    placeholder="",
    placement="bottomStart",
    disabled=False,
    cleanable=True,
    block=False,
    show_meridiem=False,
    editable=True,
    loading=False,
    min_hour=None,        # earliest selectable hour, 0-23 (hides earlier)
    max_hour=None,        # latest selectable hour, 0-23 (hides later)
    hidden_hours=None,
    hidden_minutes=None,
    hidden_seconds=None,
    help=None,            # tooltip next to the label
    locale=None,
    on_change=None,
    key=None,
) -> tuple[time | None, time | None]

Restricting selectable dates

date_picker and date_range_picker accept declarative constraints (the keyboard-only date_input / date_range_input do not, as RSuite has no calendar to disable). Callables can't cross the Python/JS boundary, so pass plain values and the frontend builds the shouldDisableDate predicate for you:

from datetime import date
from st_rsuite import date_picker

# Only weekdays in a fixed window, with a couple of holidays blocked out.
picked = date_picker(
    label="Appointment",
    min_date=date(2026, 6, 1),
    max_date=date(2026, 6, 30),
    disabled_dates=[date(2026, 6, 19)],   # individual dates
    disabled_weekdays=[5, 6],             # 0=Monday .. 6=Sunday, so Sat/Sun
    key="appt",
)

min_date / max_date are inclusive. disabled_weekdays uses the same numbering as Python's date.weekday() (Monday is 0). limit_start_year / limit_end_year bound the years reachable in the calendar, relative to the current selection.

Shortcut ranges

date_range_picker shows shortcut presets beside the calendar. It ships RSuite's defaults (Today, Yesterday, Last 7 days); pass your own with ranges, or ranges=[] to hide the sidebar entirely.

from datetime import date, timedelta
from st_rsuite import date_range_picker

today = date.today()
start, end = date_range_picker(
    label="Report window",
    ranges=[
        {"label": "Last 7 days", "value": (today - timedelta(days=6), today)},
        {"label": "Last 30 days", "value": (today - timedelta(days=29), today)},
        {"label": "This month", "value": (today.replace(day=1), today)},
    ],
    key="report",
)

Each preset is {"label": str, "value": (start, end)}, with optional "close_overlay": True (commit and close on click) and "placement": "bottom" | "left".

Inputs

Simple keyboard-only components with no popups, designed for compact quick-entry scenarios.

date_input

date_input(
    label="",
    value=None,           # date object or YYYY-MM-DD string
    format="yyyy-MM-dd",
    size="md",
    placeholder=None,
    disabled=False,
    help=None,            # tooltip next to the label
    locale=None,
    on_change=None,
    key=None,
) -> date | None

date_range_input

date_range_input(
    label="",
    value=None,           # tuple of (date, date) or (str, str)
    format="yyyy-MM-dd",
    character=" ~ ",      # separator between start and end
    size="md",
    placeholder=None,
    disabled=False,
    help=None,            # tooltip next to the label
    locale=None,
    on_change=None,
    key=None,
) -> tuple[date | None, date | None]

Selection

radio_tile

radio_tile(
    options=[...],        # list of dicts: {value, label, description?, icon?}
    value=None,           # default selected value
    inline=False,         # horizontal layout
    disabled=False,
    locale=None,
    on_change=None,
    key=None,
) -> str | None

select_picker

select_picker(
    items=[...],          # list of dicts: {value, label, group?}
    value=None,           # default selected value
    label="",             # label above the control
    searchable=True,      # show search input in the dropdown
    virtualized=False,    # virtualize very large lists
    disabled_items=None,  # values rendered non-selectable
    appearance="default", # 'default' | 'subtle'
    size="md",            # 'lg' | 'md' | 'sm' | 'xs'
    placeholder="Select",
    placement="bottomStart",
    disabled=False,
    cleanable=True,
    block=False,
    loading=False,
    help=None,            # tooltip next to the label
    locale=None,
    on_change=None,
    key=None,
) -> str | None

Options group automatically under headings when any item carries a group key.

tag_picker

tag_picker(
    items=[...],          # list of dicts: {value, label, group?}
    value=None,           # list of selected values
    label="",
    searchable=True,
    virtualized=False,
    creatable=False,      # let users create options not in items
    disabled_items=None,
    size="md",
    placeholder="Select",
    placement="bottomStart",
    disabled=False,
    cleanable=True,
    block=False,
    loading=False,
    help=None,
    locale=None,
    on_change=None,
    key=None,
    appearance="default", # 'default' | 'subtle'
) -> list[str]

Multi-select rendered as removable tags. With creatable=True, values the user types that are not in items become selectable options and come back in the return list.

check_picker

check_picker(
    items=[...],          # list of dicts: {value, label, group?}
    value=None,           # list of selected values
    label="",
    searchable=True,
    virtualized=False,
    countable=True,       # append a selection-count badge
    disabled_items=None,
    appearance="default", # 'default' | 'subtle'
    size="md",
    placeholder="Select",
    placement="bottomStart",
    disabled=False,
    cleanable=True,
    block=False,
    loading=False,
    help=None,
    locale=None,
    on_change=None,
    key=None,
) -> list[str]

Multi-select with a checkbox per option. Unlike tag_picker, the closed control shows selected labels plus a count badge instead of removable tags. The labels truncate as needed while the badge remains visible.

Tree / Hierarchical

check_tree

check_tree(
    data=[...],           # [{value, label, children?: [...]}]
    value=None,           # list of selected values
    cascade=True,         # parent/child cascade selection
    searchable=True,      # show search input
    default_expand_all=False,
    show_indent_line=False,
    height=360,           # tree height in px
    disabled=False,
    uncheckable_values=None,
    locale=None,
    on_change=None,
    key=None,
) -> list[str]

check_tree_picker

check_tree_picker(
    data=[...],           # [{value, label, children?: [...]}]
    value=None,           # list of selected values
    cascade=True,
    searchable=True,
    countable=True,       # show selected count in toggle
    appearance="default",
    size="md",
    placeholder="Select",
    placement="bottomStart",
    disabled=False,
    cleanable=True,
    block=False,
    default_expand_all=False,
    show_indent_line=False,
    height=320,
    uncheckable_values=None,
    locale=None,
    on_change=None,
    key=None,
) -> list[str]

tree_picker

tree_picker(
    data=[...],           # [{value, label, children?: [...]}]
    value=None,           # single selected value
    label="",             # label above the control
    searchable=True,
    virtualized=False,    # virtualize very large trees
    default_expand_all=False,
    show_indent_line=False,
    only_leaf_selectable=False,  # keep branch nodes unselectable
    disabled_items=None,  # values rendered non-selectable
    height=320,           # tree height in px inside the dropdown
    appearance="default",
    size="md",
    placeholder="Select",
    placement="bottomStart",
    disabled=False,
    cleanable=True,
    block=False,
    loading=False,
    help=None,            # tooltip next to the label
    locale=None,
    on_change=None,
    key=None,
) -> str | None

Single-select counterpart of check_tree_picker.

cascader

cascader(
    data=[...],           # [{value, label, children?: [...]}]
    value=None,           # single selected value
    label="",
    parent_selectable=False,  # allow non-leaf nodes as the answer
    searchable=True,
    disabled_items=None,
    column_width=156,     # width of each cascade column
    column_height=320,    # height of each cascade column
    appearance="default",
    size="md",
    placeholder="Select",
    placement="bottomStart",
    disabled=False,
    cleanable=True,
    block=False,
    loading=False,
    help=None,
    locale=None,
    on_change=None,
    key=None,
) -> str | None

Single-select counterpart of multi_cascade_tree. By default only leaf nodes are selectable; set parent_selectable=True to accept any level.

multi_cascade_tree

multi_cascade_tree(
    data=[...],           # [{value, label, children?: [...]}]
    value=None,           # list of selected values
    cascade=True,
    searchable=False,
    column_width=156,     # width of each cascade column
    column_height=320,    # height of each cascade column
    disabled=False,
    uncheckable_values=None,
    locale=None,
    on_change=None,
    key=None,
) -> list[str]

Display & Input

carousel

carousel(
    items=[...],          # src: URL/data string or explicit pathlib.Path
    autoplay=True,
    autoplay_interval=4000,  # ms between slides
    placement="bottom",   # indicator: 'top' | 'bottom' | 'left' | 'right'
    shape="dot",          # indicator: 'dot' | 'bar'
    active_index=0,
    locale=None,
    on_change=None,
    key=None,
) -> int                  # active slide index

A string src is always a browser reference and is never probed on the server filesystem. To inline an app-owned local image, pass a pathlib.Path (or another os.PathLike) chosen by the app. Local assets are limited to 10 MiB each and 20 MiB per carousel render; never construct the path object from unsanitized user input.

timeline

timeline(
    items=[...],          # [{content, time?, icon?, color?}]
    align="left",         # 'left' | 'right' | 'alternate'
    endless=False,        # continuous timeline line
    locale=None,
    key=None,
) -> None                 # display-only

The icon field accepts react-icons names (e.g. "FaCheck", "FaTruck", "MdEmail") or emoji strings as fallback. 150+ icons from Font Awesome 5 and Material Design are included.

pin_input

pin_input(
    length=6,
    value="",
    mask=False,           # password-style masking
    type="number",        # 'number' | 'alphabetic' | 'alphanumeric'
    size="md",
    placeholder="",
    disabled=False,
    read_only=False,
    otp=False,            # one-time password autocomplete
    attached=False,       # remove spacing between fields
    locale=None,
    on_change=None,
    key=None,
) -> str                  # current PIN value

Locale / i18n

All components accept a locale parameter to switch calendar labels, month/day names, and button text to the target language. RSuite ships 29 locales out of the box.

When locale is not set, the component automatically detects the browser's language (navigator.language) and uses the closest matching RSuite locale.

from st_rsuite import date_picker

# Japanese
date_picker(label="日付を選択", locale="ja_JP", one_tap=True, key="jp")

# Chinese (Simplified)
date_picker(label="选择日期", locale="zh_CN", one_tap=True, key="cn")

# Spanish
date_picker(label="Elegir fecha", locale="es_ES", one_tap=True, key="es")

Available locales: ar_EG, ca_ES, cs_CZ, da_DK, de_DE, en_GB, en_US, es_AR, es_ES, fa_IR, fi_FI, fr_FR, gu_IN, hu_HU, it_IT, ja_JP, kk_KZ, ko_KR, ne_NP, nl_NL, pl_PL, pt_BR, ru_RU, sv_SE, th_TH, tr_TR, uk_UA, zh_CN, zh_TW

Locales load lazily: a page downloads only the locale it actually renders (a few KB), never the whole set.

Running the example

uv add st-rsuite
uv run streamlit run examples/showcase.py

Development

# Clone and install
git clone https://github.com/lperezmo/st-rsuite.git
cd st-rsuite
uv sync --dev

# Build frontend
cd st_rsuite/frontend
npm install
npm run build
cd ../..

# Run showcase
uv run streamlit run examples/showcase.py

Troubleshooting

streamlit.errors.StreamlitAPIException: Component 'st-rsuite.rsuite' must be declared in pyproject.toml with asset_dir to use file-backed js

Streamlit could not find st-rsuite's bundled frontend assets when it started. Check two things:

  1. Streamlit version. st-rsuite needs Streamlit >= 1.51 (the first release with the st.components.v2 API). Upgrade and fully restart the app:

    uv add "streamlit>=1.51"      # or: pip install -U "streamlit>=1.51"
    
  2. st-rsuite install. Make sure the package is current and installed from its wheel, which ships the built assets: uv add -U st-rsuite (or pip install -U st-rsuite), then restart the app.

Disclaimer

Full disclaimer: This project was built with the help of Claude Opus 4.6 by Anthropic, using Claude Code and streamlit/agent-skills. It is heavily based on st-mui.

License

MIT

Metadata

Release files for st-rsuite 0.12.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for st-rsuite 0.12.0
File Size Uploaded
st_rsuite-0.12.0.tar.gz 372.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for st-rsuite 0.12.0
File Interpreter ABI Platform
st_rsuite-0.12.0-py3-none-any.whl Python 3 none any Details

Total release size: 764.6 kB

Release files / st_rsuite-0.12.0.tar.gz

Download URL st_rsuite-0.12.0.tar.gz
Size 372.9 kB
Tags Source
SHA-256 checksum
How to use checksums
6f5273a7ebb6db0c5914c6ff9cd69400670ea3659589b509426e12a21cd22819
BLAKE2b-256 checksum
How to use checksums
3244fd47f0717392b755bfcab778faebbc1e685a8996e7828c8eaf4db38710a3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / st_rsuite-0.12.0-py3-none-any.whl

Download URL st_rsuite-0.12.0-py3-none-any.whl
Size 391.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5438ed16e0e512a9d6c644d7833e3f368982cf95f68380fa1e401b178b8fa69c
BLAKE2b-256 checksum
How to use checksums
2c6efd6b398e8c42b1416302aecb9c8750dc4fa7cbec48e83ea4792e040f19ce
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

0.12.0 This release

2 release files

0.11.1

2 release files

0.11.0

2 release files

0.10.1

2 release files

0.9.1

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.6

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page