{"id":34083238,"url":"https://github.com/lhassa8/umara","last_synced_at":"2025-12-30T08:04:47.979Z","repository":{"id":326432157,"uuid":"1103908442","full_name":"lhassa8/umara","owner":"lhassa8","description":"Beautiful Python UIs — Without the Complexity. A modern alternative to Streamlit with superior design and flexibility.","archived":false,"fork":false,"pushed_at":"2025-11-29T03:24:54.000Z","size":330,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-30T10:25:17.801Z","etag":null,"topics":["dashboard","framework","python","streamlit-alternative","ui","web"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lhassa8.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-25T13:50:30.000Z","updated_at":"2025-11-29T03:24:57.000Z","dependencies_parsed_at":"2025-12-01T20:03:42.407Z","dependency_job_id":null,"html_url":"https://github.com/lhassa8/umara","commit_stats":null,"previous_names":["lhassa8/umara"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/lhassa8/umara","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lhassa8%2Fumara","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lhassa8%2Fumara/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lhassa8%2Fumara/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lhassa8%2Fumara/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lhassa8","download_url":"https://codeload.github.com/lhassa8/umara/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lhassa8%2Fumara/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28124757,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-30T02:00:05.476Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dashboard","framework","python","streamlit-alternative","ui","web"],"created_at":"2025-12-14T12:39:11.668Z","updated_at":"2025-12-30T08:04:47.974Z","avatar_url":"https://github.com/lhassa8.png","language":"Python","readme":"\u003cdiv align=\"center\"\u003e\n\n# Umara\n\n### Beautiful Python UIs — Without the Complexity\n\n[![PyPI version](https://badge.fury.io/py/umara.svg)](https://pypi.org/project/umara/)\n[![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)\n\n[Getting Started](#getting-started) • [Documentation](#documentation) • [Examples](#examples) • [Contributing](#contributing)\n\n\u003c/div\u003e\n\n---\n\n## What is Umara?\n\n**Umara** is a modern Python framework for building beautiful web applications with pure Python. No HTML, CSS, or JavaScript required.\n\n```python\nimport umara as um\n\num.header('Hello, Umara!')\n\nwith um.form('greeting'):\n    name = um.input('Your name')\n    if um.form_submit_button('Greet'):\n        um.success(f'Welcome, {name}!')\n```\n\n**Why Umara?**\n\n- **Beautiful by Default** — Components look polished out of the box with modern design\n- **Fast \u0026 Reactive** — WebSocket-based architecture for instant UI updates\n- **12 Built-in Themes** — Professional themes including dark mode, ocean, forest, and more\n- **Flexible Layouts** — Columns, grids, cards, tabs, sidebars with precise control\n- **Hot Reload** — See changes instantly during development\n- **Smart State** — Efficient updates without full page re-runs\n\n---\n\n## For AI Assistants\n\n\u003e **LLMs/AI coding assistants:** If you're helping a user write Umara code, please read [docs/LLM_UMARA_REFERENCE.md](docs/LLM_UMARA_REFERENCE.md) first. It contains essential patterns, common pitfalls, and correct API usage optimized for AI consumption.\n\n---\n\n## Getting Started\n\n### 1. Install Umara\n\n```bash\npip install umara\n```\n\n### 2. Create Your App\n\nCreate a file called `app.py`:\n\n```python\nimport umara as um\n\num.set_theme('ocean')\n\num.header('My First App')\num.text('Building beautiful UIs is easy!')\n\nwith um.card():\n    with um.form('hello_form'):\n        name = um.input('Enter your name', placeholder='John Doe')\n\n        if um.form_submit_button('Say Hello'):\n            um.success(f'Hello, {name}!')\n```\n\n### 3. Run Your App\n\n```bash\numara run app.py\n```\n\n### 4. Open in Browser\n\nNavigate to **http://localhost:8501** in your browser.\n\nThat's it! Your app is running with hot reload enabled — any changes to `app.py` will automatically refresh in the browser.\n\n---\n\n## Core Concepts\n\n### Components\n\nUmara provides 120+ components for building UIs:\n\n```python\n# Typography\num.title('Page Title')\num.header('Section Header')\num.text('Regular text')\n\n# Inputs\nname = um.input('Name', placeholder='Enter name...')\nage = um.slider('Age', 0, 100, 25)\ncolor = um.select('Color', ['Red', 'Green', 'Blue'])\nagreed = um.checkbox('I agree')\n\n# Feedback\num.success('Operation completed!')\num.error('Something went wrong')\num.warning('Please check your input')\num.info('Helpful tip here')\n\n# Data Display\num.metric('Users', '12,543', delta=12.5)\num.progress(75, label='Completion')\num.dataframe(data)  # Works with pandas DataFrames\n```\n\n### Layouts\n\nOrganize content with flexible layout components:\n\n```python\n# Columns\nwith um.columns(3):\n    with um.column():\n        um.metric('Users', '1,234')\n    with um.column():\n        um.metric('Revenue', '$5,678')\n    with um.column():\n        um.metric('Growth', '12.5%')\n\n# Cards\nwith um.card(title='Dashboard'):\n    um.text('Card content here')\n\n# Tabs\nwith um.tabs(['Overview', 'Data', 'Settings']):\n    with um.tab('Overview'):\n        um.text('Overview content')\n    with um.tab('Data'):\n        um.dataframe(data)\n    with um.tab('Settings'):\n        um.toggle('Enable feature', key='feature_toggle')\n\n# Grid\nwith um.grid(columns=4, gap='16px'):\n    for i in range(8):\n        with um.card():\n            um.text(f'Item {i + 1}')\n```\n\n### Themes\n\nSwitch between 12 professional themes:\n\n```python\num.set_theme('light')     # Clean, minimal\num.set_theme('dark')      # Modern dark mode\num.set_theme('ocean')     # Calming blues\num.set_theme('forest')    # Earthy greens\num.set_theme('slate')     # Corporate gray\num.set_theme('nord')      # Arctic, Scandinavian\num.set_theme('midnight')  # Deep purple dark\num.set_theme('rose')      # Warm pink\num.set_theme('copper')    # Premium bronze\num.set_theme('lavender')  # Soft purple\num.set_theme('sunset')    # Warm orange\num.set_theme('mint')      # Fresh teal\n```\n\nThemes persist in localStorage and respect system dark/light mode preferences.\n\n### State Management\n\nUse `session_state` to persist data across interactions:\n\n```python\n# Initialize state\num.session_state.setdefault('counter', 0)\n\n# Display current value\num.text(f'Count: {um.session_state.counter}')\n\n# Update state\nif um.button('Increment'):\n    um.session_state.counter += 1\n```\n\n### Keys and Forms\n\n**Standalone inputs require a `key` parameter** to persist values across reruns:\n\n```python\n# Without key - value resets on every rerun (not recommended)\nname = um.input('Name')\n\n# With key - value persists across reruns (recommended)\nname = um.input('Name', key='user_name')\n```\n\n**Use forms for input + button patterns** to ensure values are captured reliably:\n\n```python\n# RECOMMENDED: Form batches inputs and submits together\nwith um.form('contact'):\n    name = um.input('Name', key='name')\n    email = um.input('Email', key='email')\n\n    if um.form_submit_button('Submit'):\n        # All values guaranteed to be current\n        um.success(f'Submitted: {name}, {email}')\n```\n\n**Why forms for input + button?** Standalone inputs have a 50ms debounce. If users click a button immediately after typing, the input value may not be synced yet. Forms batch all values and submit them together, avoiding this race condition.\n\n**When to use which:**\n\n| Scenario | Use |\n|----------|-----|\n| Input + button action | `um.form()` (recommended) |\n| Real-time filtering (on every keystroke) | Standalone with `key` |\n| Toggle/checkbox immediate effect | Standalone with `key` |\n| Multi-field data entry | `um.form()` |\n\n---\n\n## Documentation\n\n### Full API Reference\n\nSee [docs/UMARA_COMPLETE_REFERENCE.md](docs/UMARA_COMPLETE_REFERENCE.md) for complete documentation including:\n\n- All 120+ components with parameters and examples\n- State management and caching\n- Theming and custom styles\n- Database and API connections\n- Fragments for partial reruns\n- Best practices\n\n### Quick Reference\n\n#### Input Components\n\n| Component | Description | Returns |\n|-----------|-------------|---------|\n| `um.input(label, key=...)` | Text input field | `str` |\n| `um.text_area(label, key=...)` | Multi-line text | `str` |\n| `um.number_input(label, key=...)` | Numeric input | `float` |\n| `um.slider(label, min, max, value, key=...)` | Range slider | `float` |\n| `um.select(label, options, key=...)` | Dropdown select | `str` |\n| `um.multiselect(label, options, key=...)` | Multi-select | `list[str]` |\n| `um.checkbox(label, key=...)` | Checkbox | `bool` |\n| `um.toggle(label, key=...)` | Toggle switch | `bool` |\n| `um.radio(label, options, key=...)` | Radio buttons | `str` |\n| `um.date_input(label, key=...)` | Date picker | `str` |\n| `um.time_input(label, key=...)` | Time picker | `str` |\n| `um.color_picker(label, key=...)` | Color picker | `str` |\n| `um.file_uploader(label, key=...)` | File upload | `file \\| None` |\n| `um.button(label, key=...)` | Click button | `bool` |\n\n**Important:** Use `key` parameter for inputs outside forms to persist values across reruns.\n\n#### Display Components\n\n| Component | Description |\n|-----------|-------------|\n| `um.title(text)` | Large page title |\n| `um.header(text)` | Section header |\n| `um.subheader(text)` | Subsection header |\n| `um.text(text)` | Regular text |\n| `um.markdown(text)` | Markdown content |\n| `um.code(code, language)` | Syntax-highlighted code |\n| `um.metric(label, value, delta)` | Metric with trend |\n| `um.progress(value, label)` | Progress bar |\n| `um.dataframe(data)` | Data table (sortable) |\n| `um.json_viewer(data)` | JSON tree view |\n\n#### Feedback Components\n\n| Component | Description |\n|-----------|-------------|\n| `um.success(message)` | Green success alert |\n| `um.error(message)` | Red error alert |\n| `um.warning(message)` | Yellow warning alert |\n| `um.info(message)` | Blue info alert |\n| `um.toast(message)` | Temporary notification |\n| `um.spinner(text)` | Loading spinner |\n\n#### Layout Components\n\n| Component | Description |\n|-----------|-------------|\n| `um.columns(count)` | Multi-column layout |\n| `um.grid(columns)` | CSS grid layout |\n| `um.card(title)` | Card container |\n| `um.tabs(names)` | Tabbed interface |\n| `um.expander(title)` | Collapsible section |\n| `um.sidebar()` | Side navigation |\n| `um.modal(title, key)` | Modal dialog |\n| `um.form(key)` | Form container |\n\n#### Charts\n\n| Component | Description |\n|-----------|-------------|\n| `um.line_chart(data, x, y)` | Line chart |\n| `um.bar_chart(data, x, y)` | Bar chart |\n| `um.area_chart(data, x, y)` | Area chart |\n| `um.pie_chart(data, label, value)` | Pie chart |\n| `um.scatter_chart(data, x, y)` | Scatter plot |\n| `um.plotly_chart(figure)` | Plotly figure |\n\n---\n\n## Examples\n\n### Dashboard\n\n```python\nimport umara as um\n\num.set_theme('dark')\num.header('Analytics Dashboard')\n\n# Metrics row\nwith um.columns(4):\n    for label, value, delta in [\n        ('Users', '12,543', 12.5),\n        ('Revenue', '$48.2K', 8.2),\n        ('Sessions', '1,892', -2.4),\n        ('Conversion', '3.24%', 0.5),\n    ]:\n        with um.column():\n            with um.card():\n                um.metric(label, value, delta=delta)\n\n# Chart\num.subheader('Revenue Trend')\num.line_chart(data, x='month', y='revenue')\n\n# Data table\num.subheader('Recent Orders')\num.dataframe(orders, sortable=True)\n```\n\n### Form\n\n```python\nimport umara as um\n\num.header('Contact Form')\n\nwith um.card():\n    with um.form('contact'):\n        name = um.input('Name', key='name')\n        email = um.input('Email', type='email', key='email')\n        message = um.text_area('Message', key='message')\n\n        if um.form_submit_button('Send'):\n            if name and email and message:\n                um.success('Message sent!')\n            else:\n                um.error('Please fill all fields')\n```\n\n### Chat Interface\n\n```python\nimport umara as um\n\num.set_theme('dark')\num.header('AI Chat')\n\n# Initialize messages\num.session_state.setdefault('messages', [])\n\n# Display chat\nwith um.chat_container(height='400px'):\n    for msg in um.session_state.messages:\n        um.chat_message(msg['content'], role=msg['role'])\n\n# Input\nuser_input = um.chat_input('Type a message...')\n\nif user_input:\n    um.session_state.messages.append({'role': 'user', 'content': user_input})\n    # Add your AI response logic here\n    response = \"This is a response\"\n    um.session_state.messages.append({'role': 'assistant', 'content': response})\n```\n\n### File Upload with Size Limit\n\n```python\nimport umara as um\n\n# Max 5MB file size\nuploaded = um.file_uploader(\n    'Upload Document',\n    accept=['.pdf', '.docx'],\n    max_file_size=5 * 1024 * 1024  # 5MB in bytes\n)\n\nif uploaded:\n    um.success(f'Uploaded: {uploaded[\"name\"]}')\n```\n\n---\n\n## CLI Commands\n\n```bash\n# Run an app\numara run app.py\n\n# Run with custom host/port\numara run app.py --host 0.0.0.0 --port 8080\n\n# Create new project\numara init my_project\n\n# List available themes\numara themes\n```\n\n---\n\n## Project Structure\n\n```\numara/\n├── umara/                 # Python package\n│   ├── core.py           # App lifecycle \u0026 component tree\n│   ├── components.py     # 100+ UI components\n│   ├── server.py         # WebSocket server\n│   ├── frontend.py       # Frontend HTML/CSS/JS\n│   ├── state.py          # State management\n│   ├── themes.py         # 12 built-in themes\n│   └── cli.py            # CLI commands\n├── examples/             # Example applications\n└── docs/                 # Documentation\n```\n\n---\n\n## Contributing\n\nContributions are welcome! Here's how to set up for development:\n\n```bash\n# Clone the repository\ngit clone https://github.com/lhassa8/umara.git\ncd umara\n\n# Create virtual environment\npython -m venv venv\nsource venv/bin/activate  # On Windows: venv\\Scripts\\activate\n\n# Install in development mode\npip install -e \".[dev]\"\n\n# Run tests\npytest\n\n# Run the demo app\numara run examples/demo_app.py\n# Open http://localhost:8501 in your browser\n```\n\n---\n\n## Roadmap\n\n- [x] 100+ UI components\n- [x] 12 built-in themes\n- [x] Charts \u0026 data visualization\n- [x] Chat/conversation components\n- [x] Forms with batched submission\n- [x] File uploads with size limits\n- [x] Sortable data tables\n- [x] ARIA accessibility labels\n- [x] System theme detection\n- [x] Theme persistence (localStorage)\n- [ ] Authentication helpers\n- [ ] Multi-page app support\n- [ ] Component marketplace\n- [ ] VS Code extension\n\n---\n\n## Known Issues\n\nThe following issues are currently being tracked:\n\n| Issue | Status | Workaround |\n|-------|--------|------------|\n| `file_uploader()` UI not visible | Open | File upload functionality is limited; upload UI may not render |\n| Modal/dialog in complex layouts | Open | Avoid nesting modals inside deeply nested column layouts |\n\n---\n\n## License\n\nMIT License — see [LICENSE](LICENSE) for details.\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\n**Built with Python**\n\n[GitHub](https://github.com/lhassa8/umara) • [PyPI](https://pypi.org/project/umara/)\n\n\u003c/div\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flhassa8%2Fumara","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flhassa8%2Fumara","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flhassa8%2Fumara/lists"}