Question: I'm trying to build a Shiny for Python app where portions of the form code can be broken out using Shiny Modules where I can define the specific ui and server logic as a class method, but ultimately inherit some base capability. I have the following shiny app: import pandas as pd from shiny import App, reactive, ui, module, render from abc import ABC, abstractmethod class ShinyFormTemplate(ABC): @abstractmethod @module.ui def ui_func(self): pass @abstractmethod @module.server def server_func(self, input, output, session, *args, **kwargs): pass class FruitForm(ShinyFormTemplate): @module.ui def ui_func(self): return ui.row( ui.input_text("fruits",'Select a Fruit',""), ui.output_text("output_fruit"), ui.input_text("qtys",'Quantity:',""), ui.output_text("output_qty"), ) @module.server def server_func(self, input, output, session, *args, **kwargs): @render.text def output_fruits(): return input.fruits() @render.text def output_qty(): return input.qtys() class VeggieForm(ShinyFormTemplate): @module.ui def ui_func(self): return ui.row( ui.input_radio_buttons("veggie","Select a Veggie:",{'Asparagus':'Asparagus','Spinach':'Spinach','Squash':'Squash','Lettuce':'Lettuce'}), ui.output_text("output_veggie"), ui.input_text("qtys",'Quantity:',""), ui.output_text("output_qty"), ) @module.server def server_func(self, input, output, session, *args, **kwargs): @render.text def output_veggie(): return input.veggie() @render.text def output_qty(): return input.qtys() fruits = FruitForm() veggies = VeggieForm() app_ui = ui.page_fluid( ui.page_navbar( ui.nav_panel("New Fruit", "New Fruit - Input Form", fruits.ui_func('fruit') ), ui.nav_panel("New Veggie", "New Veggie - Input Form", veggies.ui_func('veggie') ), title="Sample App", id="page", ), title="Basic App" ) def server(input, output, session): fruits.server_func('fruit') veggies.server_func('veggie') app = App(app_ui, server)  But when trying to run this, I get an error: Exception has occurred: ValueError `id` must be a single string File "C:\Users\this_user\OneDrive\Documents\Programming Projects\Python\example_class_module\app.py", line 66, in <module> fruits.ui_func('fruit') ValueError: `id` must be a single string  I do not understand this error because I thought I provided a string based id for the module namespace ('fruit' in this case). What I've Tried: I tried to define the server and ui objects outside the class and passing them in as arguments to the init() function instead of defining them as class methods. However, working this way, I don't think I can access attributes of the class instance from within the module function using self.attribute. Is it possible to define class methods as shiny module (server and ui) components?

Answer: I found a way to do all the things desired, but I'm not sure it's the best way. Welcome suggestions if there is a better way.. Instead of explicitly defining a ui or server module AS a class method, its possible to achieve similar functionality if the ui and server modules are defined INSIDE a class method and then called at the end of the method to activate the module code. Here is the basic idea: class MyForm: def __init__(self, namespace_id): # pass in other objects specific to this form, such as a dataframe to populate the form with initially self.__namespace_id = namespace_id def call_ui(self): @module.ui def ui_func(): # ui module components go here for the module return ui_func(self.__namespace_id) def call_server(self): @module.server def server_func(self, input, output, session): # server module logic goes here server_func(self.__namespace_id) form = MyForm('fruit') # the module in this class uses the 'fruit' namespace app_ui = ui.page_fluid( form.call_ui() ) def server(input, output, session): form.call_server(input, output, session) # input, output, and session must be explicitly passed into call_server method app = App(app_ui, server)  This ultimately makes it possible to build a more complex app modularly that could for example have a bunch of UI forms that capture their own specific input fields and write to their own specific database table. Below is a working example built from the question that demonstrates encapsulation of a shiny module within a class, inheritance with common module functionality defined at the parent class (ShinyFormTemplate), and polymorphic behavior where the call_server() and call_ui() methods handle the form content specific to their child class (FruitForm, and VeggieForm). Also, note that the VeggieForm class was defined with additional complexity in it's init() method to set it apart from FruitForm (see the veggie_only_data parameter that only FruitForm requires).  import pandas as pd from shiny import App, reactive, ui, module, render from abc import ABC, abstractmethod class ShinyFormTemplate(ABC): """This is the abstract base class that has some commonly defined and implemented ui and server logic methods, as well as abstract methods for ui and server logic methods that will be implemented by the children (FruitForm and VeggieForm)""" _namespace_id=None def __init__(self, namespace_id, *args, **kwargs): # will be inhereted by child classes self._namespace_id=namespace_id @abstractmethod def call_ui(self): pass @abstractmethod def call_server(self,input,output,session): pass def _common_button_ui(self): """This method gets inherited by both fruit and veggie classes, providing ui for counter button""" return ui.row( ui.column(6,ui.input_action_button('count_button',"Increment Counter")), ui.column(3,ui.output_text('show_counter')), ui.column(3), ) def _common_button_server(self,input,output,session): """This method gets inherited by both fruit and veggie classes, providing server functionality for counter button""" counter = reactive.value(0) @reactive.effect @reactive.event(input.count_button) def namespace_text(): counter.set(counter.get()+1) @render.text def show_counter(): return str(counter()) class FruitForm(ShinyFormTemplate): """This is the Fruit child class providing specific UI and Server functionality for Fruits.""" def call_ui(self): """This method defines the FruitForm specific ui module AND calls it at the end returning the result.""" @module.ui def ui_func(): return ui.row( ui.input_text("fruits",'Select a Fruit',""), ui.output_text("output_fruits"), ui.input_text("qtys",'Quantity:',""), ui.output_text("output_qty"), self._common_button_ui(), # protected method inherited from ShinyFormTemplate. # Insert additional fruit specific ui here that will operate in the 'fruit' namespace ) return ui.nav_panel("New Fruit", "New Fruit - Input Form", ui_func(self._namespace_id) # the call to establish the fruit ui has to be returned at the end of this class, so that it gets inserted into the app_ui object that is defined globally ) def call_server(self,input,output,session): """This method defines the ui module AND calls it at the end.""" @module.server def server_func(input, output, session): @render.text def output_fruits(): return input.fruits() self.__server_fruit_addl_stuff(input, output, session) # private method for FruitForm class only # Insert additional Fruit specific server logic here that will operate in the 'fruit' namespace self._common_button_server(input,output,session) # protected method inherited from ShinyFormTemplate server_func(self._namespace_id) def __server_fruit_addl_stuff(self, input, output, session): """Here is some additional server functionality that exists only in the FruitForm class and can be called by the call_server() method""" @render.text def output_qty(): return input.qtys() class VeggieForm(ShinyFormTemplate): """This is the Veggie child class providing specific UI and Server functionality for Veggies.""" def __init__(self, namespace_id, veggie_only_data, *args, **kwargs): # will be inhereted by child classes self._namespace_id=namespace_id self.__veggie_only_data=veggie_only_data def call_ui(self): """This method defines the VeggieForm specific ui module AND calls it at the end returning the result.""" @module.ui def ui_func(): return ui.row( ui.row(self.__veggie_only_data).add_style("font-weight: bold;"), ui.input_radio_buttons("veggie","Select a Veggie:",{'Asparagus':'Asparagus','Spinach':'Spinach','Squash':'Squash','Lettuce':'Lettuce'}), ui.output_text("output_veggie"), ui.input_text("qtys",'Quantity:',""), ui.output_text("output_qty"), # Insert additional Veggie specific ui here that will operate in the 'veggie' namespace self._common_button_ui(), ) return ui.nav_panel("New Veggie", "New Veggie - Input Form", ui_func(self._namespace_id) ) def call_server(self,input,output,session): @module.server def server_func(input, output, session): @render.text def output_veggie(): return input.veggie() @render.text def output_qty(): return input.qtys() # Insert additional Veggie specific server logic here that will operate in the 'veggie' namespace self._common_button_server(input, output, session) server_func(self._namespace_id) #Define fruit and veggie class object instances. This allows us to also pass in other objects like specific dataframes and database models that we can use to write populated form data to PostgreSQL database fruits = FruitForm(namespace_id='fruit') # all ui/server components will operate in the 'fruit' namespace veggies = VeggieForm(namespace_id='veggie',veggie_only_data='This class has a veggie specific data model') # all ui/server components will operate in the 'fruit' namespace food_forms = [fruits, veggies] # main ui object for the app app_ui = ui.page_fluid( ui.page_navbar( [form.call_ui() for form in food_forms], # iterate through any number of forms - creates and runs a ui module for each title="Sample App", id="page", ), title="Basic App" ) # main server function for the app def server(input, output, session): for form in food_forms: form.call_server(input, output, session) # iterate through any number of forms - creates and runs a server module for each app = App(app_ui, server)