Umara
# Umara > Beautiful Python UI framework for building web applications without HTML, CSS, or JavaScript. ## Installation ```bash pip install umara ``` ## Quick Start ```python import umara as um um.set_theme('ocean') um.header('My App') # IMPORTANT: Use forms for input + button patterns with um.form('greeting_form'): name = um.input('Your name') if um.form_submit_button('Greet'): um.success(f'Hello, {name}!') ``` Run: `umara run app.py` Open: http://localhost:8501 --- …
Unclaimed Agent
Are you the maintainer? Claim this agent to manage its listing and increase its trust score.
# Umara > Beautiful Python UI framework for building web applications without HTML, CSS, or JavaScript. ## Installation ```bash pip install umara ``` ## Quick Start ```python import umara as um um.set_theme('ocean') um.header('My App') # IMPORTANT: Use forms for input + button patterns with um.form('greeting_form'): name = um.input('Your name') if um.form_submit_button('Greet'): um.success(f'Hello, {name}!') ``` Run: `umara run app.py` Open: http://localhost:8501 --- ## CRITICAL PATTERNS ### Pattern 1: Input + Button (USE FORMS!) **WRONG** - Button may fire before input value is synced (50ms debounce): ```python # DON'T DO THIS - race condition possible name = um.input('Name', key='name') if um.button('Submit'): um.success(f'Hello {name}') # name might be stale! ``` **CORRECT** - Form batches values and submits together: ```python # DO THIS - values guaranteed to be current with um.form('my_form'): name = um.input('Name') email = um.input('Email') if um.form_submit_button('Submit'): um.success(f'Submitted: {name}, {email}') ``` ### Pattern 2: Real-time Updates (Standalone + Key) Use standalone inputs with `key` only for real-time filtering/search: ```python # Good for search - updates on every keystroke search = um.input('Search', key='search_query') filtered = [item for item in items if search.lower() in item.lower()] for item in filtered: um.text(item) ``` ### Pattern 3: Toggle/Checkbox Immediate Effect ```python dark_mode = um.toggle('Dark mode', key='dark_mode') if dark_mode: um.set_theme('dark') else: um.set_theme('light') ``` ### When to Use What | Scenario | Solution | |----------|----------| | Input + submit button | `um.form()` + `um.form_submit_button()` | | Multi-field data entry | `um.form()` | | Real-time search/filter | Standalone input with `key` | | Toggle/checkbox immediate effect | Standalone with `key` | --- ## API Reference ### Typography ```python um.header('Section Header', level=1) # level 1-6 um.subheader('Subsection') um.text('Regular text') um.text('Colored text', color='#6366f1') um.markdown('**bold** and *italic*') um.code('print("hello")', language='python') ``` ### Input Components All inputs return their current value. Use `key` parameter for persistence outside forms. ```python # Text input text = um.input( label='', key=None, # State key for persistence value='', # Default value placeholder='', type='text', # 'text', 'password', 'email', 'number' disabled=False ) # Multi-line text text = um.text_area(label='', key=None, value='', placeholder='', rows=4) # Slider num = um.slider(label='', min_value=0, max_value=100, value=None, key=None, step=1) # Number input (with increment/decrement buttons) num = um.number_input( label='Enter a number', min_value=0, max_value=100, value=50, key='num_input' ) # Select dropdown choice = um.select( label='', options=['A', 'B', 'C'], # List of strings key=None, default=None, placeholder='Select an option...' ) # Multi-select (returns list of selected items) choices = um.multiselect( label='Select items', options=['Apple', 'Banana', 'Cherry', 'Date'], default=['Apple'], key='multi_select' ) # Radio buttons option = um.radio(label='', options=['S', 'M', 'L'], key=None, default=None, horizontal=False) # Checkbox (returns bool) checked = um.checkbox(label='', key=None, value=False) # Toggle switch (returns bool) enabled = um.toggle(label='', key=None, value=False) # Date input (returns date string) selected_date = um.date_input('Select a date', key='date_pick') # Time input (returns time string) selected_time = um.time_input('Select a time', key='time_pick') # Color picker (returns hex color string) color = um.color_picker('Pick a color', value='#3b82f6', key='color_pick') # Rating (returns number of stars) rating = um.rating('Rate this', max_value=5, value=3, key='rating_input') # Pills / Segmented control (returns selected option) selection = um.pills( 'Quick filters', options=['All', 'Active', 'Completed', 'Archived'], key='pills_select' ) # Select slider (slider with discrete options) selected = um.select_slider( 'Choose a size', options=['XS', 'S', 'M', 'L', 'XL', 'XXL'], value='M', key='size_slider' ) ``` ### Buttons ```python # Click button (returns True when clicked) if um.button( label='Click me', key=None, variant='primary', # 'primary', 'secondary', 'outline', 'ghost', 'danger' disabled=False, full_width=False ): um.success('Clicked!') # Copy button (copies text to clipboard) um.copy_button('npm install umara', label='Copy install command') # Download button (triggers file download) um.download_button( label='Download CSV', data='Name,Age,City\nAlice,28,NYC\nBob,34,LA', file_name='sample.csv', mime='text/csv' ) ``` ### Forms ```python with um.form( key='my_form', clear_on_submit=False, # Clear values after submit border=True # Show border around form ): name = um.input('Name') email = um.input('Email') if um.form_submit_button(label='Submit', variant='primary'): # All values guaranteed to be current here um.success(f'Got: {name}, {email}') ``` ### Layouts ```python # Columns with um.columns(3): # Number of columns with um.column(): um.text('Column 1') with um.column(): um.text('Column 2') with um.column(): um.text('Column 3') # Grid with um.grid(columns=4, gap='16px'): for i in range(8): um.text(f'Item {i}') # Card with um.card(title='Card Title', subtitle='Optional subtitle'): um.text('Card content') # Tabs (CORRECT SYNTAX) with um.tabs(['Tab A', 'Tab B', 'Tab C'], key='main_tabs'): with um.tab(0): um.text('Content for Tab A') with um.tab(1): um.text('Content for Tab B') with um.tab(2): um.text('Content for Tab C') # Sidebar with um.sidebar(): um.header('Navigation') um.text('Sidebar content') # Expander (collapsible) with um.expander('Click to expand', expanded=False): um.text('Hidden content') # Modal (popup dialog) if um.button('Open Modal', key='open_modal_btn'): um.open_modal('my_modal') with um.modal('Modal Title', key='my_modal'): um.text('Modal content here!') modal_input = um.input('Input in modal', key='modal_input') ``` ### Data Display ```python # Metric with trend indicator um.metric(label='Users', value='12,543', delta=12.5) # Stat card (richer metric display) um.stat_card( title='Total Revenue', value='$45,231', trend=12.5, # Positive = green, negative = red trend_label='vs last month' ) # Progress bar um.progress(value=75, label='75% Complete') # Dataframe / Table sample_data = [ {'Name': 'Alice', 'Age': 28, 'City': 'New York'}, {'Name': 'Bob', 'Age': 34, 'City': 'Los Angeles'}, ] um.dataframe(sample_data, sortable=True) # JSON viewer (collapsible tree view) um.json_viewer({ 'user': {'name': 'John', 'email': 'john@example.com'}, 'items': ['apple', 'banana'], 'count': 42 }) # Badge (status indicator) um.badge('Default', variant='default') um.badge('Success', variant='success') um.badge('Warning', variant='warning') um.badge('Error', variant='error') um.badge('Info', variant='info') # Avatar (user profile image/initials) um.avatar(name='John Doe', size='sm') # sm, md, lg, xl um.avatar(name='Jane Smith', size='lg') # Breadcrumbs (navigation path) um.breadcrumbs([ {'label': 'Home', 'href': '#'}, {'label': 'Products', 'href': '#'}, {'label': 'Laptops'} # Last item has no href ]) # Steps indicator (wizard progress) um.steps(['Account', 'Profile', 'Review', 'Complete'], current=1) # Pagination page = um.pagination(total_pages=10, current_page=1, key='page') um.text(f'Current page: {page}') # Empty state (placeholder for empty content) um.empty_state( title='No results found', description='Try adjusting your search or filters.', icon='search' # 'search', 'inbox', 'document', 'folder' ) # Spinner (loading indicator) with um.spinner('Loading data...'): um.text('Content shown while loading') # Divider and spacer um.divider() um.spacer(height='24px') # HTML embed (custom HTML content) um.html('<div style="color: blue;">Custom HTML</div>') ``` ### Feedback ```python um.success('Done!') um.error('Failed') um.warning('Caution') um.info('Note') ``` ### Charts ```python # Line chart um.line_chart(data, x='month', y='sales', title='Monthly Sales') # Bar chart um.bar_chart(data, x='month', y='sales') # Area chart um.area_chart(data, x='month', y='sales') # Pie chart um.pie_chart(data, label='category', value='value') # Scatter chart scatter_data = [ {'x': 1, 'y': 2}, {'x': 2, 'y': 4}, {'x': 3, 'y': 3}, ] um.scatter_chart(scatter_data, x='x', y='y') ``` ### State Management ```python # Persist data across reruns um.session_state.setdefault('counter', 0) um.session_state.counter += 1 # Both notations work: um.session_state.counter = 5 um.session_state['counter'] = 5 ``` ### Themes ```python # 12 built-in themes um.set_theme('light') # default um.set_theme('dark') # dark mode um.set_theme('ocean') # blues um.set_theme('forest') # greens # Also: slate, nord, midnight, rose, copper, lavender, sunset, mint ``` --- ## Common Examples ### Contact Form ```python import umara as um um.header('Contact Us') with um.card(): with um.form('contact'): name = um.input('Name') email = um.input('Email', type='email') message = um.text_area('Message', rows=5) if um.form_submit_button('Send Message'): if not all([name, email, message]): um.error('Please fill all fields') else: um.success('Message sent!') ``` ### Dashboard with Stat Cards ```python import umara as um um.set_theme('dark') um.header('Dashboard') with um.columns(3): with um.column(): um.stat_card( title='Total Revenue', value='$45,231', trend=12.5, trend_label='vs last month' ) with um.column(): um.stat_card( title='Active Users', value='2,345', trend=-3.2, trend_label='vs last week' ) with um.column(): um.stat_card( title='Orders', value='1,234', trend=8.1, trend_label='vs yesterday' ) # Data table sample_data = [ {'Name': 'Alice', 'Age': 28, 'City': 'New York', 'Score': 95}, {'Name': 'Bob', 'Age': 34, 'City': 'Los Angeles', 'Score': 87}, ] um.dataframe(sample_data, sortable=True) ``` ### Search with Live Filtering ```python import umara as um items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry'] # Real-time search - use key, no form needed search = um.input('Search fruits', key='search') filtered = [item for item in items if search.lower() in item.lower()] for item in filtered: um.text(f'- {item}') ``` ### Settings with Sidebar ```python import umara as um with um.sidebar(): um.header('Settings') dark = um.toggle('Dark mode', key='dark_mode') show_details = um.checkbox('Show details', key='show_details') if dark: um.set_theme('dark') else: um.set_theme('light') um.header('Content') um.text('Main content here') if show_details: with um.expander('Details', expanded=True): um.text('Extra information...') ``` ### Tabbed Interface ```python import umara as um um.header('Product Details') with um.tabs(['Overview', 'Specs', 'Reviews'], key='product_tabs'): with um.tab(0): um.text('Product overview content here') um.badge('In Stock', variant='success') with um.tab(1): um.json_viewer({ 'dimensions': '10x5x3 inches', 'weight': '2.5 lbs', 'color': 'Black' }) with um.tab(2): um.rating('Average Rating', max_value=5, value=4, key='avg_rating') um.text('Based on 128 reviews') ``` ### Multi-Step Form with Steps Indicator ```python import umara as um um.header('Registration') um.session_state.setdefault('step', 0) um.steps(['Account', 'Profile', 'Confirm'], current=um.session_state.step) if um.session_state.step == 0: with um.form('step1'): email = um.input('Email', type='email') password = um.input('Password', type='password') if um.form_submit_button('Next'): um.session_state.step = 1 elif um.session_state.step == 1: with um.form('step2'): name = um.input('Full Name') bio = um.text_area('Bio') if um.form_submit_button('Next'): um.session_state.step = 2 else: um.success('Registration complete!') if um.button('Start Over', key='reset'): um.session_state.step = 0 ``` ### Counter with State ```python import umara as um um.header('Counter Example') um.session_state.setdefault('counter', 0) um.text(f'Count: {um.session_state.counter}') with um.columns(2): with um.column(): if um.button('Increment', key='inc'): um.session_state.counter += 1 with um.column(): if um.button('Reset', variant='outline', key='reset'): um.session_state.counter = 0 ``` ### Modal Dialog ```python import umara as um um.header('Modal Example') if um.button('Open Settings', key='open_settings'): um.open_modal('settings_modal') with um.modal('Settings', key='settings_modal'): um.text('Configure your preferences:') theme = um.select('Theme', options=['Light', 'Dark', 'Ocean'], key='theme_select') notifications = um.toggle('Enable notifications', key='notif_toggle') um.text(f'Theme: {theme}, Notifications: {notifications}') ``` --- ## CLI Commands ```bash umara run app.py # Run app umara run app.py --port 8080 # Custom port umara init my_project # Create new project umara themes # List themes ``` ## Documentation Full API: docs/UMARA_COMPLETE_REFERENCE.md GitHub: https://github.com/lhassa8/umara PyPI: https://pypi.org/project/umara/