diff --git a/api/etemplate.php b/api/etemplate.php
index f66ddc3768..1b6dbbbc6e 100644
--- a/api/etemplate.php
+++ b/api/etemplate.php
@@ -346,6 +346,26 @@ function send_template()
 					(substr($matches[ADD_ET2_PREFIX_LAST_GROUP], -1) === '/' ? substr($matches[ADD_ET2_PREFIX_LAST_GROUP], 0, -1) .
 						'></et2-' . $matches[3] : $matches[ADD_ET2_PREFIX_LAST_GROUP]) . '>';
 			}, $str);
+
+			// change all attribute-names of new et2-* widgets to camelCase
+			$str = preg_replace_callback('/<et2-([a-z-]+)\s([^>]+)>/', static function(array $matches)
+			{
+				preg_match_all('/(^| )([a-z\d_-]+)="([^"]+)"/i', $matches[2], $attrs, PREG_PATTERN_ORDER);
+				$attrs = array_combine($attrs[2], $attrs[3]);
+
+				foreach($attrs as $name => $value)
+				{
+					if (count($parts = preg_split('/[_-]/', $name)) > 1)
+					{
+						$attrs[array_shift($parts).implode('', array_map('ucfirst', $parts))] = $value;
+						unset($attrs[$name]);
+					}
+				}
+				$ret = str_replace($matches[2], implode(' ', array_map(static function ($name, $value) {
+						return $name . '="' . $value . '"';
+					}, array_keys($attrs), $attrs)).(substr($matches[2], -1) === '/' ? '/' : ''), $matches[0]);
+				return $ret;
+			}, $str);
 		}
 		$processing = microtime(true);
 
diff --git a/api/js/etemplate/Et2Avatar/Et2Avatar.ts b/api/js/etemplate/Et2Avatar/Et2Avatar.ts
index 416df578d0..2f1ee025ee 100644
--- a/api/js/etemplate/Et2Avatar/Et2Avatar.ts
+++ b/api/js/etemplate/Et2Avatar/Et2Avatar.ts
@@ -20,7 +20,7 @@ import {cropperStyles} from "./cropperStyles";
 
 export class Et2Avatar extends Et2Widget(SlotMixin(SlAvatar)) implements et2_IDetachedDOM
 {
-	private _contact_id;
+	private _contactId;
 	private _delBtn: HTMLElement;
 	private _editBtn : HTMLElement;
 
@@ -60,7 +60,7 @@ export class Et2Avatar extends Et2Widget(SlotMixin(SlAvatar)) implements et2_IDe
 			/**
 			 * Contact id should be either user account_id {account:number} or contact_id {contact:number or number}
 			 */
-			contact_id:{type: String},
+			contactId:{type: String},
 
 			/**
 			 * Image
@@ -96,7 +96,7 @@ export class Et2Avatar extends Et2Widget(SlotMixin(SlAvatar)) implements et2_IDe
 		super();
 		this.src = "";
 		this.label = "";
-		this.contact_id = "";
+		this.contactId = "";
 		this.editable = false;
 		this.crop = false;
 		this.size = "2.7em";
@@ -125,11 +125,11 @@ export class Et2Avatar extends Et2Widget(SlotMixin(SlAvatar)) implements et2_IDe
 	firstUpdated()
 	{
 		let self = this;
-		if (this.contact_id && this.editable)
+		if (this.contactId && this.editable)
 		{
 			egw(window).json(
 				'addressbook.addressbook_ui.ajax_noPhotoExists',
-				[this.contact_id],
+				[this.contactId],
 				function(noPhotoExists)
 				{
 					if (noPhotoExists) self.image="";
@@ -140,54 +140,54 @@ export class Et2Avatar extends Et2Widget(SlotMixin(SlAvatar)) implements et2_IDe
 	}
 
 
-	get contact_id()
+	get contactId()
 	{
-		return this._contact_id;
+		return this._contactId;
 	}
 
 	/**
-	 * Function to set contact id
-	 * contact id could be in one of these formats:
+	 * Function to set contactId
+	 * contactId could be in one of these formats:
 	 *		'number', will be consider as contact_id
 	 *		'contact:number', similar to above
 	 *		'account:number', will be consider as account id
-	 * @example: contact_id = "account:4"
+	 * @example: contactId = "account:4"
 	 *
-	 * @param {string} _contact_id contact id could be as above mentioned formats
+	 * @param {string} _contactId contact id could be as above mentioned formats
 	 */
-	set contact_id(_contact_id : string)
+	set contactId(_contactId : string)
 	{
 		let params = {};
-		let id = 'contact_id';
+		let id = 'contactId';
 
-		if (!_contact_id)
+		if (!_contactId)
 		{
-			_contact_id = this.egw().user('account_id');
+			_contactId = this.egw().user('account_id');
 		}
-		else if(_contact_id.match(/account:/))
+		else if(_contactId.match(/account:/))
 		{
 			id = 'account_id';
-			_contact_id = _contact_id.replace('account:','');
+			_contactId = _contactId.replace('account:','');
 		}
 		else
 		{
-			id = 'contact_id';
-			_contact_id = _contact_id.replace('contact:', '');
+			id = 'contactId';
+			_contactId = _contactId.replace('contact:', '');
 		}
-		let oldContactId = this._contact_id;
-		this._contact_id = _contact_id;
+		let oldContactId = this._contactId;
+		this._contactId = _contactId;
 		// if our src (incl. cache-buster) already includes the correct id, use that one
-		if (!this.src || !this.src.match("(&|\\?)contact_id="+_contact_id+"(&|\\$)"))
+		if (!this.src || !this.src.match("(&|\\?)contact_id="+_contactId+"(&|\\$)"))
 		{
-			params[id] = _contact_id;
+			params[id] = _contactId;
 			this.src  = egw.link('/api/avatar.php',params);
 		}
-		this.requestUpdate("contact_id", oldContactId);
+		this.requestUpdate("contactId", oldContactId);
 	}
 
 	set value(_value)
 	{
-		this.contact_id = _value;
+		this.contactId = _value;
 	}
 
 	/**
@@ -247,7 +247,7 @@ export class Et2Avatar extends Et2Widget(SlotMixin(SlAvatar)) implements et2_IDe
 			{"button_id": 0, label: this.egw().lang('cancel'), id: 'cancel', image: 'cancelled'}
 		];
 		const value = {
-			contact_id: this.contact_id,
+			contactId: this.contactId,
 			src: this.image
 		}
 		this._editDialog(egw.lang('Edit avatar'), value, buttons, null);
@@ -387,7 +387,7 @@ export class Et2Avatar extends Et2Widget(SlotMixin(SlAvatar)) implements et2_IDe
 	 */
 	getDetachedAttributes(_attrs : string[])
 	{
-		_attrs.push("contact_id", "label", "href", "src", "image");
+		_attrs.push("contactId", "label", "href", "src", "image");
 	}
 
 	getDetachedNodes()
diff --git a/api/js/etemplate/Et2Date/Et2DateDuration.ts b/api/js/etemplate/Et2Date/Et2DateDuration.ts
index ece4c05602..8d1e857247 100644
--- a/api/js/etemplate/Et2Date/Et2DateDuration.ts
+++ b/api/js/etemplate/Et2Date/Et2DateDuration.ts
@@ -18,11 +18,11 @@ import {FormControlMixin} from "@lion/form-core";
 
 export interface formatOptions
 {
-	select_unit : string;
-	display_format : string;
-	data_format : string;
-	hours_per_day : number;
-	empty_not_0 : boolean;
+	selectUnit : string;
+	displayFormat : string;
+	dataFormat : string;
+	hoursPerDay : number;
+	emptyNot0 : boolean;
 	number_format? : string;
 };
 
@@ -39,19 +39,19 @@ export function formatDuration(value : number | string, options : formatOptions)
 	// Handle empty / 0 / no value
 	if(value === "" || value == "0" || !value)
 	{
-		return {value: options.empty_not_0 ? "0" : "", unit: ""};
+		return {value: options.emptyNot0 ? "0" : "", unit: ""};
 	}
 	// Make sure it's a number now
 	value = typeof value == "string" ? parseInt(value) : value;
 
-	if(!options.select_unit)
+	if(!options.selectUnit)
 	{
 		let vals = [];
-		for(let i = 0; i < options.display_format.length; ++i)
+		for(let i = 0; i < options.displayFormat.length; ++i)
 		{
-			let unit = options.display_format[i];
+			let unit = options.displayFormat[i];
 			let val = this._unit_from_value(value, unit, i === 0);
-			if(unit === 's' || unit === 'm' || unit === 'h' && options.display_format[0] === 'd')
+			if(unit === 's' || unit === 'm' || unit === 'h' && options.displayFormat[0] === 'd')
 			{
 				vals.push(sprintf('%02d', val));
 			}
@@ -64,10 +64,10 @@ export function formatDuration(value : number | string, options : formatOptions)
 	}
 
 	// Put value into minutes for further processing
-	switch(options.data_format)
+	switch(options.dataFormat)
 	{
 		case 'd':
-			value *= options.hours_per_day;
+			value *= options.hoursPerDay;
 		// fall-through
 		case 'h':
 			value *= 60;
@@ -78,16 +78,16 @@ export function formatDuration(value : number | string, options : formatOptions)
 	}
 
 	// Figure out the best unit for display
-	let _unit = options.display_format == "d" ? "d" : "h";
-	if(options.display_format.indexOf('m') > -1 && value < 60)
+	let _unit = options.displayFormat == "d" ? "d" : "h";
+	if(options.displayFormat.indexOf('m') > -1 && value < 60)
 	{
 		_unit = 'm';
 	}
-	else if(options.display_format.indexOf('d') > -1 && value >= (60 * options.hours_per_day))
+	else if(options.displayFormat.indexOf('d') > -1 && value >= (60 * options.hoursPerDay))
 	{
 		_unit = 'd';
 	}
-	let out_value = "" + (_unit == 'm' ? value : (Math.round((value / 60.0 / (_unit == 'd' ? options.hours_per_day : 1)) * 100) / 100));
+	let out_value = "" + (_unit == 'm' ? value : (Math.round((value / 60.0 / (_unit == 'd' ? options.hoursPerDay : 1)) * 100) / 100));
 
 	if(out_value === '')
 	{
@@ -163,7 +163,7 @@ export class Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement)
 			 *
 			 * Units to read/store the data.  'd' = days (float), 'h' = hours (float), 'm' = minutes (int), 's' = seconds (int).
 			 */
-			data_format: {
+			dataFormat: {
 				reflect: true,
 				type: String
 			},
@@ -174,7 +174,7 @@ export class Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement)
 			 * 'd' = days, 'h' = hours, 'm' = minutes, 's' = seconds.  Use combinations to give a choice.
 			 * Default is 'dh' = days or hours with selectbox.
 			 */
-			display_format: {
+			displayFormat: {
 				reflect: true,
 				type: String
 			},
@@ -185,7 +185,7 @@ export class Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement)
 			 * Display a unit-selection for multiple units, or an input field per unit.
 			 * Default is true
 			 */
-			select_unit: {
+			selectUnit: {
 				reflect: true,
 				type: Boolean
 			},
@@ -195,7 +195,7 @@ export class Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement)
 			 *
 			 * Allows to enter a percentage instead of numbers
 			 */
-			percent_allowed: {
+			percentAllowed: {
 				type: Boolean
 			},
 
@@ -205,7 +205,7 @@ export class Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement)
 			 * Number of hours in a day, used for converting between hours and (working) days.
 			 * Default 8
 			 */
-			hours_per_day: {
+			hoursPerDay: {
 				reflect: true,
 				type: Number
 			},
@@ -216,7 +216,7 @@ export class Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement)
 			 * Should the widget differ between 0 and empty, which get then returned as NULL
 			 * Default false, empty is considered as 0
 			 */
-			empty_not_0: {
+			emptyNot0: {
 				reflect: true,
 				type: Boolean
 			},
@@ -226,7 +226,7 @@ export class Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement)
 			 *
 			 * use d/h/m instead of day/hour/minute
 			 */
-			short_labels: {
+			shortLabels: {
 				reflect: true,
 				type: Boolean
 			},
@@ -250,22 +250,22 @@ export class Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement)
 		super();
 
 		// Property defaults
-		this.data_format = "m";
-		this.display_format = "dhm";
-		this.select_unit = true;
-		this.percent_allowed = false;
-		this.hours_per_day = 8;
-		this.empty_not_0 = false;
-		this.short_labels = false;
+		this.dataFormat = "m";
+		this.displayFormat = "dhm";
+		this.selectUnit = true;
+		this.percentAllowed = false;
+		this.hoursPerDay = 8;
+		this.emptyNot0 = false;
+		this.shortLabels = false;
 
 		this.formatter = formatDuration;
 	}
 
 	transformAttributes(attrs)
 	{
-		// Clean formats, but avoid things that need to be expanded like $cont[display_format]
+		// Clean formats, but avoid things that need to be expanded like $cont[displayFormat]
 		const check = new RegExp('[\$\@' + Object.keys(Et2DateDuration.time_formats).join('') + ']');
-		for(let attr in ["display_format", "data_format"])
+		for(let attr in ["displayFormat", "dataFormat"])
 		{
 			if(typeof attrs[attrs] === 'string' && !check.test(attrs[attr]))
 			{
@@ -281,45 +281,45 @@ export class Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement)
 	{
 		let value = 0;
 
-		if(!this.select_unit)
+		if(!this.selectUnit)
 		{
 			for(let i = this._durationNode.length; --i >= 0;)
 			{
 				value += parseInt(<string>this._durationNode[i].value) * this._unit2seconds(this._durationNode[i].name);
 			}
-			if(this.data_format !== 's')
+			if(this.dataFormat !== 's')
 			{
-				value /= this._unit2seconds(this.data_format);
+				value /= this._unit2seconds(this.dataFormat);
 			}
-			return "" + (this.data_format === 'm' ? Math.round(value) : value);
+			return "" + (this.dataFormat === 'm' ? Math.round(value) : value);
 		}
 
 		let val = this._durationNode.length ? this._durationNode[0].value.replace(',', '.') : "";
 		if(val === '')
 		{
-			return this.empty_not_0 ? '' : "0";
+			return this.emptyNot0 ? '' : "0";
 		}
 		value = parseFloat(val);
 
 		// Put value into minutes for further processing
-		switch(this._formatNode && this._formatNode.value ? this._formatNode.value : this.display_format)
+		switch(this._formatNode && this._formatNode.value ? this._formatNode.value : this.displayFormat)
 		{
 			case 'd':
-				value *= this.hours_per_day;
+				value *= this.hoursPerDay;
 			// fall-through
 			case 'h':
 				value *= 60;
 				break;
 		}
 		// Minutes should be an integer.  Floating point math.
-		if(this.data_format !== 's')
+		if(this.dataFormat !== 's')
 		{
 			value = Math.round(value);
 		}
-		switch(this.data_format)
+		switch(this.dataFormat)
 		{
 			case 'd':
-				value /= this.hours_per_day;
+				value /= this.hoursPerDay;
 			// fall-through
 			case 'h':
 				value /= 60.0;
@@ -343,23 +343,23 @@ export class Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement)
 	 *
 	 * @param {string} value
 	 */
-	set display_format(value : string)
+	set displayFormat(value : string)
 	{
-		this.__display_format = "";
+		this.__displayFormat = "";
 		// Display format must be in decreasing size order (dhms) or the calculations
 		// don't work out nicely
 		for(let f of Object.keys(Et2DateDuration.time_formats))
 		{
 			if(value.indexOf(f) !== -1)
 			{
-				this.__display_format += f;
+				this.__displayFormat += f;
 			}
 		}
 	}
 
-	get display_format()
+	get displayFormat()
 	{
-		return this.__display_format;
+		return this.__displayFormat;
 	}
 
 	/**
@@ -388,14 +388,14 @@ export class Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement)
 	 */
 	protected _convert_to_display(_value)
 	{
-		if(!this.select_unit)
+		if(!this.selectUnit)
 		{
 			let vals = [];
-			for(let i = 0; i < this.display_format.length; ++i)
+			for(let i = 0; i < this.displayFormat.length; ++i)
 			{
-				let unit = this.display_format[i];
+				let unit = this.displayFormat[i];
 				let val = this._unit_from_value(_value, unit, i === 0);
-				if(unit === 's' || unit === 'm' || unit === 'h' && this.display_format[0] === 'd')
+				if(unit === 's' || unit === 'm' || unit === 'h' && this.displayFormat[0] === 'd')
 				{
 					vals.push(sprintf('%02d', val));
 				}
@@ -409,10 +409,10 @@ export class Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement)
 		if(_value)
 		{
 			// Put value into minutes for further processing
-			switch(this.data_format)
+			switch(this.dataFormat)
 			{
 				case 'd':
-					_value *= this.hours_per_day;
+					_value *= this.hoursPerDay;
 				// fall-through
 				case 'h':
 					_value *= 60;
@@ -424,17 +424,17 @@ export class Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement)
 		}
 
 		// Figure out best unit for display
-		var _unit = this.display_format == "d" ? "d" : "h";
-		if(this.display_format.indexOf('m') > -1 && _value && _value < 60)
+		var _unit = this.displayFormat == "d" ? "d" : "h";
+		if(this.displayFormat.indexOf('m') > -1 && _value && _value < 60)
 		{
 			_unit = 'm';
 		}
-		else if(this.display_format.indexOf('d') > -1 && _value >= 60 * this.hours_per_day)
+		else if(this.displayFormat.indexOf('d') > -1 && _value >= 60 * this.hoursPerDay)
 		{
 			_unit = 'd';
 		}
-		_value = this.empty_not_0 && _value === '' || !this.empty_not_0 && !_value ? '' :
-				 (_unit == 'm' ? parseInt(_value) : (Math.round((_value / 60.0 / (_unit == 'd' ? this.hours_per_day : 1)) * 100) / 100));
+		_value = this.emptyNot0 && _value === '' || !this.emptyNot0 && !_value ? '' :
+				 (_unit == 'm' ? parseInt(_value) : (Math.round((_value / 60.0 / (_unit == 'd' ? this.hoursPerDay : 1)) * 100) / 100));
 
 		if(_value === '')
 		{
@@ -463,13 +463,13 @@ export class Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement)
 			case 'h':
 				return 3600;
 			case 'd':
-				return 3600 * this.hours_per_day;
+				return 3600 * this.hoursPerDay;
 		}
 	}
 
 	private _unit_from_value(_value, _unit, _highest)
 	{
-		_value *= this._unit2seconds(this.data_format);
+		_value *= this._unit2seconds(this.dataFormat);
 		// get value for given _unit
 		switch(_unit)
 		{
@@ -480,14 +480,14 @@ export class Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement)
 				return _highest ? _value : _value % 60;
 			case 'h':
 				_value = Math.floor(_value / 3600);
-				return _highest ? _value : _value % this.hours_per_day;
+				return _highest ? _value : _value % this.hoursPerDay;
 			case 'd':
-				return Math.floor(_value / 3600 / this.hours_per_day);
+				return Math.floor(_value / 3600 / this.hoursPerDay);
 		}
 	}
 
 	/**
-	 * Render the needed number inputs according to select_unit & display_format properties
+	 * Render the needed number inputs according to selectUnit & displayFormat properties
 	 *
 	 * @returns {any}
 	 * @protected
@@ -496,7 +496,7 @@ export class Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement)
 	{
 		let inputs = [];
 		let value = typeof this._display.value === "number" ? this._display.value : (this._display.value.split(":") || []);
-		for(let i = this.select_unit ? 1 : this.display_format.length; i > 0; --i)
+		for(let i = this.selectUnit ? 1 : this.displayFormat.length; i > 0; --i)
 		{
 			let input = {
 				name: "",
@@ -505,13 +505,13 @@ export class Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement)
 				min: undefined,
 				max: undefined
 			};
-			if(!this.select_unit)
+			if(!this.selectUnit)
 			{
 				input.min = 0;
-				input.name = this.display_format[this.display_format.length - i];
+				input.name = this.displayFormat[this.displayFormat.length - i];
 				// @ts-ignore - it doesn't like that it may have been an array
-				input.value = <string>(value[this.display_format.length - i]);
-				switch(this.display_format[this.display_format.length - i])
+				input.value = <string>(value[this.displayFormat.length - i]);
+				switch(this.displayFormat[this.displayFormat.length - i])
 				{
 					case 's':
 						input.max = 60;
@@ -540,7 +540,7 @@ export class Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement)
 	}
 
 	/**
-	 * Generate the format selector according to the select_unit and display_format properties
+	 * Generate the format selector according to the selectUnit and displayFormat properties
 	 *
 	 * @returns {any}
 	 * @protected
@@ -548,22 +548,22 @@ export class Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement)
 	protected _formatTemplate()
 	{
 		// If no formats or only 1 format, no need for a selector
-		if(!this.display_format || this.display_format.length < 1 ||
-			(!this.select_unit && this.display_format.length > 1))
+		if(!this.displayFormat || this.displayFormat.length < 1 ||
+			(!this.selectUnit && this.displayFormat.length > 1))
 		{
 			return html``;
 		}
 		// Get translations
 		this.time_formats = this.time_formats || {
-			d: this.short_labels ? this.egw().lang("d") : this.egw().lang("Days"),
-			h: this.short_labels ? this.egw().lang("h") : this.egw().lang("Hours"),
-			m: this.short_labels ? this.egw().lang("m") : this.egw().lang("Minutes"),
-			s: this.short_labels ? this.egw().lang("s") : this.egw().lang("Seconds")
+			d: this.shortLabels ? this.egw().lang("d") : this.egw().lang("Days"),
+			h: this.shortLabels ? this.egw().lang("h") : this.egw().lang("Hours"),
+			m: this.shortLabels ? this.egw().lang("m") : this.egw().lang("Minutes"),
+			s: this.shortLabels ? this.egw().lang("s") : this.egw().lang("Seconds")
 		};
 		// It would be nice to use an et2-select here, but something goes weird with the styling
 		return html`
             <select>
-                ${[...this.display_format].map((format : string) =>
+                ${[...this.displayFormat].map((format : string) =>
                         html`
                             <option value=${format} ?selected=${this._display.unit === format}>
                                 ${this.time_formats[format]}
diff --git a/api/js/etemplate/Et2Date/Et2DateDurationReadonly.ts b/api/js/etemplate/Et2Date/Et2DateDurationReadonly.ts
index ebffbc3dcb..2a18ad71de 100644
--- a/api/js/etemplate/Et2Date/Et2DateDurationReadonly.ts
+++ b/api/js/etemplate/Et2Date/Et2DateDurationReadonly.ts
@@ -37,7 +37,7 @@ export class Et2DateDurationReadonly extends Et2DateDuration
 		super();
 
 		// Property defaults
-		this.select_unit = false;	// otherwise just best matching unit will be used for eg. display_format "h:m:s"
+		this.selectUnit = false;	// otherwise just best matching unit will be used for eg. display_format "h:m:s"
 	}
 
 	get value()
@@ -55,12 +55,12 @@ export class Et2DateDurationReadonly extends Et2DateDuration
 		let parsed = this.__value;
 
 		const format_options = <formatOptions>{
-			select_unit: this.select_unit,
-			display_format: this.display_format,
-			data_format: this.data_format,
-			number_format: this.egw().preference("number_format"),
-			hours_per_day: this.hours_per_day,
-			empty_not_0: this.empty_not_0
+			selectUnit: this.selectUnit,
+			displayFormat: this.displayFormat,
+			dataFormat: this.dataFormat,
+			numberFormat: this.egw().preference("number_format"),
+			hoursPerDay: this.hoursPerDay,
+			emptyNot0: this.emptyNot0
 		};
 
 		const display = this.formatter(parsed, format_options);
diff --git a/api/js/etemplate/Et2Description/Et2Description.ts b/api/js/etemplate/Et2Description/Et2Description.ts
index fde86462cf..cbff611118 100644
--- a/api/js/etemplate/Et2Description/Et2Description.ts
+++ b/api/js/etemplate/Et2Description/Et2Description.ts
@@ -41,7 +41,7 @@ export class Et2Description extends Et2Widget(LitElement) implements et2_IDetach
 			 * Scan the value, and if there are any links (URL, mailto:) then wrap them in a clickable
 			 * <a/> tag
 			 */
-			activate_links: {
+			activeLinks: {
 				type: Boolean,
 				reflect: true
 			},
@@ -49,14 +49,14 @@ export class Et2Description extends Et2Widget(LitElement) implements et2_IDetach
 			 * Extra link target
 			 * Goes with href.  If provided, that's the target for opening the link.
 			 */
-			extra_link_target: {
+			extraLinkTarget: {
 				type: String,
 				reflect: true
 			},
 			/**
 			 * widthxheight, if popup should be used, eg. 640x480
 			 */
-			extra_link_popup: {
+			extraLinkPopup: {
 				type: String,
 				reflect: true
 			},
@@ -77,9 +77,9 @@ export class Et2Description extends Et2Widget(LitElement) implements et2_IDetach
 		super();
 
 		// Initialize properties
-		this.activate_links = false;
-		this.extra_link_popup = "";
-		this.extra_link_target = "_browser";
+		this.activeLinks = false;
+		this.extraLinkPopup = "";
+		this.extraLinkTarget = "_browser";
 		// Don't initialize this to avoid href(unknown) when rendered
 		//this.href = "";
 		this.value = "";
@@ -118,7 +118,7 @@ export class Et2Description extends Et2Widget(LitElement) implements et2_IDetach
 		}
 
 		// Do we do this here, or in transformAttributes()?
-		if(_value && !this.no_lang)
+		if(_value && !this.noLang)
 		{
 			_value = this.egw().lang(_value);
 		}
@@ -137,7 +137,7 @@ export class Et2Description extends Et2Widget(LitElement) implements et2_IDetach
 		super.requestUpdate(...arguments);
 		// Due to how we do the rendering into the light DOM (not sure it's right) we need this after
 		// value change or it won't actually show up
-		if(["value", "href", "activate_links"].indexOf(attribute) != -1 && this.parentNode)
+		if(["value", "href", "activeLinks"].indexOf(attribute) != -1 && this.parentNode)
 		{
 			this.updateComplete.then(() => render(this._renderContent(), <HTMLElement><unknown>this));
 		}
@@ -160,9 +160,9 @@ export class Et2Description extends Et2Widget(LitElement) implements et2_IDetach
 			render = this.wrapLink(this.href, this.value);
 		}
 		// If we want to activate links inside, do that
-		else if(this.activate_links && this.value)
+		else if(this.activeLinks && this.value)
 		{
-			render = this.getActivatedValue(this.value, this.href ? this.extra_link_target : '_blank');
+			render = this.getActivatedValue(this.value, this.href ? this.extraLinkTarget : '_blank');
 		}
 		// Just do the value
 		else
@@ -184,7 +184,7 @@ export class Et2Description extends Et2Widget(LitElement) implements et2_IDetach
 	async firstUpdated()
 	{
 		this.removeEventListener('click.extra_link', this._handleClick);
-		if(this.extra_link_popup || this.mime)
+		if(this.extraLinkPopup || this.mime)
 		{
 			// Add click listener
 			this.addEventListener('click.extra_link', this._handleClick);
@@ -196,9 +196,9 @@ export class Et2Description extends Et2Widget(LitElement) implements et2_IDetach
 		// call super to get the onclick handling running
 		super._handleClick(_ev);
 
-		if(this.mime_data || this.href)
+		if(this.mimeData || this.href)
 		{
-			egw(window).open_link(this.mime_data || this.href, this.extra_link_target, this.extra_link_popup, null, null, this.mime);
+			egw(window).open_link(this.mimeData || this.href, this.extraLinkTarget, this.extraLinkPopup, null, null, this.mime);
 		}
 		_ev.preventDefault();
 		return false;
diff --git a/api/js/etemplate/Et2Description/test/Et2Description.test.ts b/api/js/etemplate/Et2Description/test/Et2Description.test.ts
index 01dff9cc79..71c75a60cc 100644
--- a/api/js/etemplate/Et2Description/test/Et2Description.test.ts
+++ b/api/js/etemplate/Et2Description/test/Et2Description.test.ts
@@ -47,7 +47,7 @@ describe("Textbox widget", () =>
 		let value = "This is my value";
 
 		// Turn off translation
-		element.no_lang = true;
+		element.noLang = true;
 
 		element.set_value(value);
 
diff --git a/api/js/etemplate/Et2Dialog/Et2DialogContent.ts b/api/js/etemplate/Et2Dialog/Et2DialogContent.ts
index 51ec5920ce..ea8c415c66 100644
--- a/api/js/etemplate/Et2Dialog/Et2DialogContent.ts
+++ b/api/js/etemplate/Et2Dialog/Et2DialogContent.ts
@@ -30,7 +30,7 @@ export class Et2DialogContent extends Et2Widget(LitElement)
 			...super.properties(),
 
 			message: String,
-			dialog_type: Number,
+			dialogType: Number,
 			icon: String,
 			value: Object
 		}
@@ -39,7 +39,7 @@ export class Et2DialogContent extends Et2Widget(LitElement)
 	/**
 	 * Details for dialog type options
 	 */
-	private readonly _dialog_types : any = [
+	private readonly _dialogTypes : any = [
 		//PLAIN_MESSAGE: 0
 		"",
 		//INFORMATION_MESSAGE: 1,
@@ -57,7 +57,7 @@ export class Et2DialogContent extends Et2Widget(LitElement)
 		super();
 
 		this.icon = "";
-		this.dialog_type = 0;
+		this.dialogType = 0;
 	}
 
 	/**
@@ -74,9 +74,9 @@ export class Et2DialogContent extends Et2Widget(LitElement)
 
 	render()
 	{
-		let icon = this.icon || this.parentNode.egw().image(this._dialog_types[this.dialog_type]) || "";
+		let icon = this.icon || this.parentNode.egw().image(this._dialogTypes[this.dialogType]) || "";
 		return html`
-            <div class="dialog ${this._dialog_types[this.dialog_type]}">
+            <div class="dialog ${this._dialogTypes[this.dialogType]}">
                 <img class="dialog_icon" src=${icon}/>
                 <slot>Empty dialog - add some content</slot>
             </div>
diff --git a/api/js/etemplate/Et2Favorites/Et2Favorites.ts b/api/js/etemplate/Et2Favorites/Et2Favorites.ts
index ba7cda01fc..bdefa7aa2b 100644
--- a/api/js/etemplate/Et2Favorites/Et2Favorites.ts
+++ b/api/js/etemplate/Et2Favorites/Et2Favorites.ts
@@ -88,7 +88,7 @@ export class Et2Favorites extends Et2DropdownButton implements et2_INextmatchHea
 		return {
 			...super.properties,
 			// Where we keep the "default" preference
-			default_pref: {type: String},
+			defaultPref: {type: String},
 			// Application to show favorites for
 			app: {type: String},
 			// Extra filters to include in the saved favorite
@@ -121,7 +121,7 @@ export class Et2Favorites extends Et2DropdownButton implements et2_INextmatchHea
 			this.id = "favorite";
 		}
 
-		this._preferred = <string>this.egw().preference(this.default_pref, this.app);
+		this._preferred = <string>this.egw().preference(this.defaultPref, this.app);
 
 		// Need to wait until update is done and these exist
 		this.updateComplete.then(() =>
@@ -177,7 +177,7 @@ export class Et2Favorites extends Et2DropdownButton implements et2_INextmatchHea
 		super.updated(changedProperties);
 		if(changedProperties.has("app"))
 		{
-			this._preferred = <string>this.egw().preference(this.default_pref, this.app);
+			this._preferred = <string>this.egw().preference(this.defaultPref, this.app);
 			this.__select_options = this._load_favorites(this.app);
 			this.requestUpdate("select_options");
 		}
@@ -341,7 +341,7 @@ export class Et2Favorites extends Et2DropdownButton implements et2_INextmatchHea
 
 		// Save as default favorite - used when you click the button
 		let pref = _ev.target.value;
-		this.egw().set_preference(this.app, this.default_pref, pref);
+		this.egw().set_preference(this.app, this.defaultPref, pref);
 		this._preferred = pref;
 		this.dropdownNode.hide();
 		this.requestUpdate();
diff --git a/api/js/etemplate/Et2Image/Et2Image.ts b/api/js/etemplate/Et2Image/Et2Image.ts
index 9cbc4e0bec..7b1df2e64b 100644
--- a/api/js/etemplate/Et2Image/Et2Image.ts
+++ b/api/js/etemplate/Et2Image/Et2Image.ts
@@ -58,7 +58,7 @@ export class Et2Image extends Et2Widget(SlotMixin(LitElement)) implements et2_ID
 			 * Default image
 			 * Image to use if src is not found
 			 */
-			default_src: {type: String},
+			defaultSrc: {type: String},
 
 			/**
 			 * Link Target
@@ -70,13 +70,13 @@ export class Et2Image extends Et2Widget(SlotMixin(LitElement)) implements et2_ID
 			 * Link target
 			 * Link target descriptor
 			 */
-			extra_link_target: {type: String},
+			extraLinkTarget: {type: String},
 
 			/**
 			 * Popup
 			 * widthxheight, if popup should be used, eg. 640x480
 			 */
-			extra_link_popup: {type: String},
+			extraLinkPopup: {type: String},
 		}
 	}
 
@@ -94,11 +94,11 @@ export class Et2Image extends Et2Widget(SlotMixin(LitElement)) implements et2_ID
 	{
 		super();
 		this.src = "";
-		this.default_src = "";
+		this.defaultSrc = "";
 		this.href = "";
 		this.label = "";
-		this.extra_link_target = "_self";
-		this.extra_link_popup = "";
+		this.extraLinkTarget = "_self";
+		this.extraLinkPopup = "";
 
 		this._handleClick = this._handleClick.bind(this);
 	}
@@ -110,7 +110,7 @@ export class Et2Image extends Et2Widget(SlotMixin(LitElement)) implements et2_ID
 
 	_imageTemplate()
 	{
-		let src = this.parse_href(this.src) || this.parse_href(this.default_src);
+		let src = this.parse_href(this.src) || this.parse_href(this.defaultSrc);
 		if(!src)
 		{
 			// Hide if no valid image
@@ -150,7 +150,7 @@ export class Et2Image extends Et2Widget(SlotMixin(LitElement)) implements et2_ID
 	{
 		if(this.href)
 		{
-			this.egw().open_link(this.href, this.extra_link_target, this.extra_link_popup);
+			this.egw().open_link(this.href, this.extraLinkTarget, this.extraLinkPopup);
 		}
 		else
 		{
@@ -173,7 +173,7 @@ export class Et2Image extends Et2Widget(SlotMixin(LitElement)) implements et2_ID
 
 		if(changedProperties.has("src") && this._img)
 		{
-			this._img.setAttribute("src", this.parse_href(this.src) || this.parse_href(this.default_src));
+			this._img.setAttribute("src", this.parse_href(this.src) || this.parse_href(this.defaultSrc));
 		}
 		// if there's an href or onclick, make it look clickable
 		if(changedProperties.has("href") || typeof this.onclick !== "undefined")
diff --git a/api/js/etemplate/Et2Link/Et2Link.ts b/api/js/etemplate/Et2Link/Et2Link.ts
index c88a6832f1..5e443ae949 100644
--- a/api/js/etemplate/Et2Link/Et2Link.ts
+++ b/api/js/etemplate/Et2Link/Et2Link.ts
@@ -19,7 +19,7 @@ import {et2_IDetachedDOM} from "../et2_core_interfaces";
  * Display a specific, single entry from an application
  *
  * The entry is specified with the application name, and the app's ID for that entry.
- * You can set it directly in the properties (application, entry_id) or use set_value() to
+ * You can set it directly in the properties (application, entryId) or use set_value() to
  * pass an object {app: string, id: string, [title: string]} or string in the form <application>::<ID>.
  * If title is not specified, it will be fetched using framework's egw.link_title()
  */
@@ -65,12 +65,12 @@ export class Et2Link extends ExposeMixin<Et2Widget>(Et2Widget(LitElement)) imple
 			/**
 			 * Application entry ID
 			 */
-			entry_id: {
+			entryId: {
 				type: String,
 				reflect: true
 			},
 			/**
-			 * Pass value as an object, will be parsed to set application & entry_id
+			 * Pass value as an object, will be parsed to set application & entryId
 			 */
 			value: {
 				type: Object,
@@ -82,7 +82,7 @@ export class Et2Link extends ExposeMixin<Et2Widget>(Et2Widget(LitElement)) imple
 			 * [view|edit|add]
 			 * default "view"
 			 */
-			link_hook: {
+			linkHook: {
 				type: String
 			},
 			/**
@@ -90,20 +90,20 @@ export class Et2Link extends ExposeMixin<Et2Widget>(Et2Widget(LitElement)) imple
 			 *
 			 * Passed to egw.open() to open entry in specified application
 			 */
-			target_app: {
+			targetApp: {
 				type: String
 			},
 			/**
 			 * Optional parameter to be passed to egw().open in order to open links in specified target eg. _blank
 			 */
-			extra_link_target: {
+			extraLinkTarget: {
 				type: String
 			},
 
 			/**
 			 * Breaks title into multiple lines based on this delimiter by replacing it with '\r\n'"
 			 */
-			break_title: {
+			breakTitle: {
 				type: String
 			}
 
@@ -120,7 +120,7 @@ export class Et2Link extends ExposeMixin<Et2Widget>(Et2Widget(LitElement)) imple
 	{
 		super();
 		this._title = "";
-		this.__link_hook = "view";
+		this.__linkHook = "view";
 	}
 
 	connectedCallback()
@@ -137,12 +137,12 @@ export class Et2Link extends ExposeMixin<Et2Widget>(Et2Widget(LitElement)) imple
 	{
 		let title = this.title;
 
-		if(this.break_title)
+		if(this.breakTitle)
 		{
 			// Set up title to optionally break on the provided character - replace all space with nbsp, add a
 			// zero-width space after the break string
 			title = title
-				.replace(this.break_title, this.break_title.trimEnd() + "\u200B")
+				.replace(this.breakTitle, this.breakTitle.trimEnd() + "\u200B")
 				.replace(/ /g, '\u00a0');
 		}
 		return html`${title}`;
@@ -165,7 +165,7 @@ export class Et2Link extends ExposeMixin<Et2Widget>(Et2Widget(LitElement)) imple
 	 */
 	get value() : LinkInfo | string
 	{
-		return this.app && this.entry_id ? this.app + ":" + this.entry_id : "";
+		return this.app && this.entryId ? this.app + ":" + this.entryId : "";
 	}
 
 	set value(_value : LinkInfo | string)
@@ -173,7 +173,7 @@ export class Et2Link extends ExposeMixin<Et2Widget>(Et2Widget(LitElement)) imple
 		if(!_value)
 		{
 			this.app = "";
-			this.entry_id = "";
+			this.entryId = "";
 			this.title = "";
 			return;
 		}
@@ -200,7 +200,7 @@ export class Et2Link extends ExposeMixin<Et2Widget>(Et2Widget(LitElement)) imple
 		if(typeof _value !== "string")
 		{
 			this.app = _value.app;
-			this.entry_id = _value.id;
+			this.entryId = _value.id;
 			this._title = Et2Link.MISSING_TITLE;
 
 			if(_value.title)
@@ -210,7 +210,7 @@ export class Et2Link extends ExposeMixin<Et2Widget>(Et2Widget(LitElement)) imple
 			Object.keys(_value).forEach(key =>
 			{
 				// Skip these, they're either handled explicitly, or ID which we don't want to mess with
-				if(["app", "entry_id", "title", "id"].indexOf(key) != -1)
+				if(["app", "entryId", "title", "id"].indexOf(key) != -1)
 				{
 					return;
 				}
@@ -229,7 +229,7 @@ export class Et2Link extends ExposeMixin<Et2Widget>(Et2Widget(LitElement)) imple
 	{
 		let info = <ExposeValue><unknown>{
 			app: this.app,
-			id: this.entry_id,
+			id: this.entryId,
 			path: this.dataset['icon']
 		};
 		info['label'] = this.title;
@@ -242,7 +242,7 @@ export class Et2Link extends ExposeMixin<Et2Widget>(Et2Widget(LitElement)) imple
 		if(!info.path && this.app == "file")
 		{
 			// Fallback to check the "normal" place if path wasn't available
-			info.path = "/webdav.php/apps/" + this.dataset.app2 + "/" + this.dataset.id2 + "/" + this.entry_id;
+			info.path = "/webdav.php/apps/" + this.dataset.app2 + "/" + this.dataset.id2 + "/" + this.entryId;
 		}
 
 		if(typeof info["type"] !== "undefined")
@@ -255,7 +255,7 @@ export class Et2Link extends ExposeMixin<Et2Widget>(Et2Widget(LitElement)) imple
 	}
 
 	/**
-	 * If app or entry_id has changed, we'll update the title
+	 * If app or entryId has changed, we'll update the title
 	 *
 	 * @param changedProperties
 	 */
@@ -264,16 +264,16 @@ export class Et2Link extends ExposeMixin<Et2Widget>(Et2Widget(LitElement)) imple
 		super.willUpdate(changedProperties);
 
 		super.requestUpdate();
-		if(changedProperties.has("app") || changedProperties.has("entry_id"))
+		if(changedProperties.has("app") || changedProperties.has("entryId"))
 		{
-			if(this.app && this.entry_id && !this._title)
+			if(this.app && this.entryId && !this._title)
 			{
 				this._title = Et2Link.MISSING_TITLE;
 			}
-			if(this.app && this.entry_id && this._title == Et2Link.MISSING_TITLE)
+			if(this.app && this.entryId && this._title == Et2Link.MISSING_TITLE)
 			{
 				// Title will be fetched from server and then set
-				this._titlePromise = this.egw()?.link_title(this.app, this.entry_id, true).then(title =>
+				this._titlePromise = this.egw()?.link_title(this.app, this.entryId, true).then(title =>
 				{
 					this._title = title;
 					// It's probably already been rendered
@@ -285,8 +285,8 @@ export class Et2Link extends ExposeMixin<Et2Widget>(Et2Widget(LitElement)) imple
 
 	_handleClick(_ev : MouseEvent) : boolean
 	{
-		// If we don't have app & entry_id, nothing we can do
-		if(!this.app || !this.entry_id || typeof this.entry_id !== "string")
+		// If we don't have app & entryId, nothing we can do
+		if(!this.app || !this.entryId || typeof this.entryId !== "string")
 		{
 			return false;
 		}
@@ -295,8 +295,8 @@ export class Et2Link extends ExposeMixin<Et2Widget>(Et2Widget(LitElement)) imple
 		{
 			this.egw().open(Object.assign({
 				app: this.app,
-				id: this.entry_id
-			}, this.dataset), "", this.link_hook, this.dataset.extra_args, this.target_app || this.app, this.target_app);
+				id: this.entryId
+			}, this.dataset), "", this.linkHook, this.dataset.extra_args, this.targetApp || this.app, this.targetApp);
 		}
 
 		_ev.stopImmediatePropagation();
@@ -305,7 +305,7 @@ export class Et2Link extends ExposeMixin<Et2Widget>(Et2Widget(LitElement)) imple
 
 	getDetachedAttributes(_attrs : string[])
 	{
-		_attrs.push("app", "entry_id");
+		_attrs.push("app", "entryId");
 	}
 
 	getDetachedNodes() : HTMLElement[]
diff --git a/api/js/etemplate/Et2Link/Et2LinkAdd.ts b/api/js/etemplate/Et2Link/Et2LinkAdd.ts
index 32a6a4cc98..9737cfe723 100644
--- a/api/js/etemplate/Et2Link/Et2LinkAdd.ts
+++ b/api/js/etemplate/Et2Link/Et2LinkAdd.ts
@@ -42,7 +42,7 @@ export class Et2LinkAdd extends Et2InputWidget(FormControlMixin(ValidateMixin(Sl
 			/**
 			 * Limit to the listed applications (comma seperated)
 			 */
-			application_list: {type: String}
+			applicationList: {type: String}
 		}
 	}
 
@@ -53,18 +53,18 @@ export class Et2LinkAdd extends Et2InputWidget(FormControlMixin(ValidateMixin(Sl
 			app: () =>
 			{
 				const app = <Et2LinkAppSelect>document.createElement("et2-link-apps");
-				app.app_icons = false;
+				app.appIcons = false;
 				if(this.application)
 				{
-					app.only_app = this.application;
+					app.onlyApp = this.application;
 				}
 				else if(typeof this._value !== "undefined" && this._value.app)
 				{
 					app.value = this._value.app;
 				}
-				if(this.application_list)
+				if(this.applicationList)
 				{
-					app.application_list = this.application_list;
+					app.applicationList = this.applicationList;
 				}
 				return app;
 			},
@@ -119,9 +119,9 @@ export class Et2LinkAdd extends Et2InputWidget(FormControlMixin(ValidateMixin(Sl
 		{
 			this._appNode.only_app = this.only_app;
 		}
-		if(changedProperties.has("application_list"))
+		if(changedProperties.has("applicationList"))
 		{
-			this._appNode.application_list = this.application_list;
+			this._appNode.applicationList = this.applicationList;
 		}
 		if(changedProperties.has("app_icons"))
 		{
@@ -201,4 +201,4 @@ export class Et2LinkAdd extends Et2InputWidget(FormControlMixin(ValidateMixin(Sl
 	}
 }
 
-customElements.define("et2-link-add", Et2LinkAdd);
+customElements.define("et2-link-add", Et2LinkAdd);
\ No newline at end of file
diff --git a/api/js/etemplate/Et2Link/Et2LinkAppSelect.ts b/api/js/etemplate/Et2Link/Et2LinkAppSelect.ts
index c11cf90ef2..3cb9c5e81e 100644
--- a/api/js/etemplate/Et2Link/Et2LinkAppSelect.ts
+++ b/api/js/etemplate/Et2Link/Et2LinkAppSelect.ts
@@ -15,7 +15,7 @@ export class Et2LinkAppSelect extends SlotMixin(Et2Select)
 				display: inline-block;
 				min-width: 64px;
 			}
-			:host([app_icons]) {
+			:host([appIcons]) {
 				max-width: 75px;
 			}
 			.select__menu {
@@ -37,15 +37,15 @@ export class Et2LinkAppSelect extends SlotMixin(Et2Select)
 			/**
 			 * Limit to just this one application, and hide the selection
 			 */
-			"only_app": {type: String},
+			onlyApp: {type: String},
 			/**
 			 * Limit to these applications (comma seperated).
 			 */
-			"application_list": {type: String},
+			applicationList: {type: String},
 			/**
 			 * Show application icons instead of application names
 			 */
-			"app_icons": {type: Boolean, reflect: true}
+			appIcons: {type: Boolean, reflect: true}
 		}
 	};
 
@@ -65,8 +65,8 @@ export class Et2LinkAppSelect extends SlotMixin(Et2Select)
 		}
 	}
 
-	protected __application_list : string[];
-	protected __only_app : string;
+	protected __applicationList : string[];
+	protected __onlyApp : string;
 
 	/**
 	 * Constructor
@@ -75,9 +75,9 @@ export class Et2LinkAppSelect extends SlotMixin(Et2Select)
 	constructor()
 	{
 		super();
-		this.only_app = "";
-		this.app_icons = true;
-		this.application_list = [];
+		this.onlyApp = "";
+		this.appIcons = true;
+		this.applicationList = [];
 		this.hoist = true;
 
 		// Select options are based off abilities registered with link system
@@ -86,19 +86,19 @@ export class Et2LinkAppSelect extends SlotMixin(Et2Select)
 		this._handleChange = this._handleChange.bind(this);
 	}
 
-	set only_app(app : string)
+	set onlyApp(app : string)
 	{
-		this.__only_app = app || "";
+		this.__onlyApp = app || "";
 		this.updateComplete.then(() =>
 		{
-			this.style.display = this.only_app ? 'none' : '';
+			this.style.display = this.onlyApp ? 'none' : '';
 		});
 	}
 
-	get only_app() : string
+	get onlyApp() : string
 	{
-		// __only_app may be undefined during creation
-		return this.__only_app || "";
+		// __onlyApp may be undefined during creation
+		return this.__onlyApp || "";
 	}
 
 	connectedCallback()
@@ -121,7 +121,7 @@ export class Et2LinkAppSelect extends SlotMixin(Et2Select)
 		// Register to
 		this.addEventListener("change", this._handleChange);
 
-		if(this.__only_app)
+		if(this.__onlyApp)
 		{
 			this.style.display = 'none';
 		}
@@ -142,31 +142,31 @@ export class Et2LinkAppSelect extends SlotMixin(Et2Select)
 	{
 		super.willUpdate(changedProperties);
 
-		if(changedProperties.has("only_app") || changedProperties.has("application_list"))
+		if(changedProperties.has("onlyApp") || changedProperties.has("applicationList"))
 		{
 			this._reset_select_options();
 		}
 	}
 
-	set application_list(app_list : string[])
+	set applicationList(app_list : string[])
 	{
-		let oldValue = this.__application_list;
+		let oldValue = this.__applicationList;
 		if(typeof app_list == "string")
 		{
 			app_list = (<string>app_list).split(",");
 		}
-		this.__application_list = app_list;
-		this.requestUpdate("application_list", oldValue);
+		this.__applicationList = app_list;
+		this.requestUpdate("applicationList", oldValue);
 	}
 
-	get application_list() : string[]
+	get applicationList() : string[]
 	{
-		return this.__application_list;
+		return this.__applicationList;
 	}
 
 	get value() : string
 	{
-		return this.only_app ? this.only_app : <string>super.value;
+		return this.onlyApp ? this.onlyApp : <string>super.value;
 	}
 
 	set value(new_value)
@@ -197,13 +197,13 @@ export class Et2LinkAppSelect extends SlotMixin(Et2Select)
 		let select_options = [];
 
 		// Limit to one app
-		if(this.only_app)
+		if(this.onlyApp)
 		{
-			select_options.push({value: this.only_app, label: this.egw().lang(this.only_app)});
+			select_options.push({value: this.onlyApp, label: this.egw().lang(this.onlyApp)});
 		}
-		else if(this.application_list.length > 0)
+		else if(this.applicationList.length > 0)
 		{
-			select_options = this.application_list;
+			select_options = this.applicationList;
 		}
 		else
 		{
@@ -226,7 +226,7 @@ export class Et2LinkAppSelect extends SlotMixin(Et2Select)
 	{
 		return html`
             <sl-menu-item value="${option.value}" title="${option.title}">
-                ${this.app_icons ? "" : option.label}
+                ${this.appIcons ? "" : option.label}
                 ${this._iconTemplate(option.value)}
             </sl-menu-item>`;
 	}
diff --git a/api/js/etemplate/Et2Link/Et2LinkEntry.ts b/api/js/etemplate/Et2Link/Et2LinkEntry.ts
index d3bfa3fc7b..4ce0a19029 100644
--- a/api/js/etemplate/Et2Link/Et2LinkEntry.ts
+++ b/api/js/etemplate/Et2Link/Et2LinkEntry.ts
@@ -46,15 +46,15 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin(
 			/**
 			 * Limit to just this application - hides app selection
 			 */
-			only_app: {type: String},
+			onlyApp: {type: String},
 			/**
 			 * Limit to the listed applications (comma seperated)
 			 */
-			application_list: {type: String},
+			applicationList: {type: String},
 			/**
 			 * Show just application icons instead of names
 			 */
-			app_icons: {type: Boolean},
+			appIcons: {type: Boolean},
 			/**
 			 * Callback before query to server.
 			 * It will be passed the request & et2_link_entry objects.  Must return true, or false to abort query.
@@ -79,9 +79,9 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin(
 			app: () =>
 			{
 				const app = <Et2LinkAppSelect>document.createElement("et2-link-apps")
-				if(this.__only_app)
+				if(this.__onlyApp)
 				{
-					app.only_app = this.__only_app;
+					app.onlyApp = this.__onlyApp;
 				}
 				else if(typeof this._value !== "undefined" && this._value.app)
 				{
@@ -117,7 +117,7 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin(
 	 */
 	private _value : LinkInfo;
 
-	protected __only_app : string;
+	protected __onlyApp : string;
 
 	constructor()
 	{
@@ -158,28 +158,28 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin(
 			this._searchNode.readonly = this.readonly;
 		}
 		// Pass some properties on to app selection
-		if(changedProperties.has("only_app"))
+		if(changedProperties.has("onlyApp"))
 		{
-			this._appNode.only_app = this.only_app;
+			this._appNode.onlyApp = this.onlyApp;
 		}
-		if(changedProperties.has("application_list"))
+		if(changedProperties.has("applicationList"))
 		{
-			this._appNode.application_list = this.application_list;
+			this._appNode.applicationList = this.applicationList;
 		}
-		if(changedProperties.has("app_icons"))
+		if(changedProperties.has("appIcons"))
 		{
-			this._appNode.app_icons = this.app_icons;
+			this._appNode.appIcons = this.appIcons;
 		}
 	}
 
-	set only_app(app)
+	set onlyApp(app)
 	{
-		this.__only_app = app || "";
+		this.__onlyApp = app || "";
 
-		// If initial value got set before only_app, it still needs app in pre-render value
+		// If initial value got set before onlyApp, it still needs app in pre-render value
 		if(this._value && app)
 		{
-			this._value.app = this.__only_app;
+			this._value.app = this.__onlyApp;
 		}
 		if(app)
 		{
@@ -187,13 +187,13 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin(
 		}
 		if(this._appNode)
 		{
-			this._appNode.only_app = app;
+			this._appNode.onlyApp = app;
 		}
 	}
 
-	get only_app()
+	get onlyApp()
 	{
-		return this.__only_app;
+		return this.__onlyApp;
 	}
 
 	set app(app)
@@ -291,7 +291,7 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin(
 
 	/**
 	 * Option select dropdown opened
-	 * Show app selection (Et2LinkAppSelect controls own visibility according to only_app)
+	 * Show app selection (Et2LinkAppSelect controls own visibility according to onlyApp)
 	 * @param event
 	 * @protected
 	 */
@@ -302,7 +302,7 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin(
 
 	/**
 	 * Option select dropdown closed
-	 * Hide app selection (Et2LinkAppSelect controls own visibility according to only_app)
+	 * Hide app selection (Et2LinkAppSelect controls own visibility according to onlyApp)
 	 * only if there's a value selected
 	 *
 	 * @param event
@@ -318,7 +318,7 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin(
 
 	get value() : LinkInfo | string | number
 	{
-		if(this.only_app)
+		if(this.onlyApp)
 		{
 			return <string>this._searchNode?.value;
 		}
@@ -331,7 +331,7 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(ValidateMixin(
 
 	set value(val : LinkInfo | string | number)
 	{
-		let value : LinkInfo = {app: this.only_app || this.app, id: ""};
+		let value : LinkInfo = {app: this.onlyApp || this.app, id: ""};
 
 		if(typeof val === 'string' && val.length > 0)
 		{
diff --git a/api/js/etemplate/Et2Link/Et2LinkString.ts b/api/js/etemplate/Et2Link/Et2LinkString.ts
index 14bdea6959..1520005b5c 100644
--- a/api/js/etemplate/Et2Link/Et2LinkString.ts
+++ b/api/js/etemplate/Et2Link/Et2LinkString.ts
@@ -63,7 +63,7 @@ export class Et2LinkString extends Et2Widget(LitElement) implements et2_IDetache
 			/**
 			 * Application entry ID
 			 */
-			entry_id: {
+			entryId: {
 				type: String,
 				reflect: true
 			},
@@ -72,22 +72,22 @@ export class Et2LinkString extends Et2Widget(LitElement) implements et2_IDetache
 			 * Set to an appname or comma separated list of applications to show only linked entries from those
 			 * applications
 			 */
-			only_app: {
+			onlyApp: {
 				type: String
 			},
 			/**
 			 * Type filter
 			 * Sub-type key to list only entries of that type
 			 */
-			link_type: {
+			linkType: {
 				type: String
 			},
 
 			// Show links that are marked as deleted, being held for purge
-			show_deleted: {type: Boolean},
+			showDeleted: {type: Boolean},
 
 			/**
-			 * Pass value as an object, will be parsed to set application & entry_id
+			 * Pass value as an object, will be parsed to set application & entryId
 			 */
 			value: {
 				type: Object,
@@ -103,7 +103,7 @@ export class Et2LinkString extends Et2Widget(LitElement) implements et2_IDetache
 	{
 		super();
 		this._link_list = []
-		this.__show_deleted = false;
+		this.__showDeleted = false;
 	}
 
 
@@ -126,7 +126,7 @@ export class Et2LinkString extends Et2Widget(LitElement) implements et2_IDetache
 		if(typeof _value == 'object' && !Array.isArray(_value) && _value.to_app && _value.to_id)
 		{
 			this.application = _value.to_app;
-			this.entry_id = _value.to_id;
+			this.entryId = _value.to_id;
 			this.get_links();
 			return;
 		}
@@ -173,7 +173,7 @@ export class Et2LinkString extends Et2Widget(LitElement) implements et2_IDetache
 	protected _linkTemplate(link) : TemplateResult
 	{
 		return html`
-            <et2-link app="${link.app}" entry_id="${link.id}" .value=${link} ._parent=${this}></et2-link>`;
+            <et2-link app="${link.app}" entryId="${link.id}" .value=${link} ._parent=${this}></et2-link>`;
 	}
 
 	/**
@@ -236,9 +236,9 @@ export class Et2LinkString extends Et2Widget(LitElement) implements et2_IDetache
 		}
 		let _value = {
 			to_app: this.application,
-			to_id: this.entry_id,
-			only_app: this.only_app,
-			show_deleted: this.show_deleted
+			to_id: this.entryId,
+			onlyApp: this.onlyApp,
+			showDeleted: this.showDeleted
 		};
 		if(this._loadingPromise)
 		{
@@ -256,7 +256,7 @@ export class Et2LinkString extends Et2Widget(LitElement) implements et2_IDetache
 
 	getDetachedAttributes(_attrs : string[])
 	{
-		_attrs.push("application", "entry_id");
+		_attrs.push("application", "entryId");
 	}
 
 	getDetachedNodes() : HTMLElement[]
diff --git a/api/js/etemplate/Et2Link/Et2LinkTo.ts b/api/js/etemplate/Et2Link/Et2LinkTo.ts
index fb4043e333..cd6f0804de 100644
--- a/api/js/etemplate/Et2Link/Et2LinkTo.ts
+++ b/api/js/etemplate/Et2Link/Et2LinkTo.ts
@@ -41,15 +41,15 @@ export class Et2LinkTo extends Et2InputWidget(ScopedElementsMixin(FormControlMix
 			/**
 			 * Hide buttons to attach files
 			 */
-			no_files: {type: Boolean},
+			noFiles: {type: Boolean},
 			/**
 			 * Limit to just this application - hides app selection
 			 */
-			only_app: {type: String},
+			onlyApp: {type: String},
 			/**
 			 * Limit to the listed applications (comma seperated)
 			 */
-			application_list: {type: String},
+			applicationList: {type: String},
 
 			value: {type: Object}
 		}
@@ -98,7 +98,7 @@ export class Et2LinkTo extends Et2InputWidget(ScopedElementsMixin(FormControlMix
 	constructor()
 	{
 		super();
-		this.no_files = false;
+		this.noFiles = false;
 
 		this.handleFilesUploaded = this.handleFilesUploaded.bind(this);
 		this.handleEntrySelected = this.handleEntrySelected.bind(this);
@@ -120,8 +120,8 @@ export class Et2LinkTo extends Et2InputWidget(ScopedElementsMixin(FormControlMix
 	_inputGroupInputTemplate()
 	{
 		return html`
-            <et2-link-entry .only_app="${this.only_app}"
-                            .application_list="${this.application_list}"
+            <et2-link-entry .onlyApp="${this.onlyApp}"
+                            .applicationList="${this.applicationList}"
                             @sl-select=${this.handleEntrySelected}
                             @sl-clear="${this.handleEntryCleared}">
             </et2-link-entry>
@@ -134,7 +134,7 @@ export class Et2LinkTo extends Et2InputWidget(ScopedElementsMixin(FormControlMix
 	// TODO: Replace when they're webcomponents
 	_fileButtons()
 	{
-		if(this.no_files)
+		if(this.noFiles)
 		{
 			return "";
 		}
@@ -408,9 +408,9 @@ export class Et2LinkTo extends Et2InputWidget(ScopedElementsMixin(FormControlMix
 		{
 			let selected = this.select.value;
 			// Extra complicated because LinkEntry doesn't always return a LinkInfo
-			if(this.only_app)
+			if(this.onlyApp)
 			{
-				selected = <LinkInfo>{app: this.only_app, id: selected};
+				selected = <LinkInfo>{app: this.onlyApp, id: selected};
 			}
 			link_info.push(<LinkInfo>selected);
 		}
diff --git a/api/js/etemplate/Et2Nextmatch/ColumnSelection.ts b/api/js/etemplate/Et2Nextmatch/ColumnSelection.ts
index 1ca136a685..7bc02464f9 100644
--- a/api/js/etemplate/Et2Nextmatch/ColumnSelection.ts
+++ b/api/js/etemplate/Et2Nextmatch/ColumnSelection.ts
@@ -152,7 +152,7 @@ export class Et2ColumnSelection extends Et2InputWidget(LitElement)
 	protected footerTemplate()
 	{
 		let autoRefresh = html`
-            <et2-select id="nm_autorefresh" empty_label="Refresh" statustext="Automatically refresh list"
+            <et2-select id="nm_autorefresh" emptyLabel="Refresh" statustext="Automatically refresh list"
                         value="${this.__autoRefresh}">
             </et2-select>
 		`;
@@ -162,7 +162,7 @@ export class Et2ColumnSelection extends Et2InputWidget(LitElement)
 		return html`
             ${this.__autoRefresh !== false ? autoRefresh : ''}
             ${!apps['admin'] ? '' : html`
-                <et2-select id="default_preference" empty_label="${this.egw().lang("Preference")}">
+                <et2-select id="default_preference" emptyLabel="${this.egw().lang("Preference")}">
                 </et2-select>`
             }
 		`;
diff --git a/api/js/etemplate/Et2Nextmatch/Headers/CustomFilterHeader.ts b/api/js/etemplate/Et2Nextmatch/Headers/CustomFilterHeader.ts
index 0c5cb8cf54..c0cb48c62e 100644
--- a/api/js/etemplate/Et2Nextmatch/Headers/CustomFilterHeader.ts
+++ b/api/js/etemplate/Et2Nextmatch/Headers/CustomFilterHeader.ts
@@ -11,8 +11,8 @@ import {html, LitElement} from "@lion/core";
  */
 export class Et2CustomFilterHeader extends FilterMixin(Et2InputWidget(LitElement))
 {
-	private widget_type : string;
-	private widget_options : {};
+	private widgetType : string;
+	private widgetOptions : {};
 	private filter_node : Et2InputWidgetInterface & LitElement;
 
 	static get properties()
@@ -23,41 +23,41 @@ export class Et2CustomFilterHeader extends FilterMixin(Et2InputWidget(LitElement
 			/**
 			 * tag of widget we want to use to filter
 			 */
-			widget_type: {type: String},
+			widgetType: {type: String},
 
 			/**
 			 * Attributes / properties used for the filter widget
 			 */
-			widget_options: {type: Object}
+			widgetOptions: {type: Object}
 		};
 	}
 
 	constructor(...args : any[])
 	{
 		super();
-		this.widget_type = "et2-description";
-		this.widget_options = {};
+		this.widgetType = "et2-description";
+		this.widgetOptions = {};
 	}
 
 	transformAttributes(attrs)
 	{
 		super.transformAttributes(attrs);
 
-		switch(attrs.widget_type)
+		switch(attrs.widgetType)
 		{
 			case "link-entry":
-				this.widget_type = 'et2-nextmatch-header-entry';
+				this.widgetType = 'et2-nextmatch-header-entry';
 				break;
 			default:
-				this.widget_type = attrs.widget_type;
+				this.widgetType = attrs.widgetType;
 				// Prefer webcomponent, if legacy type was sent
-				if(window.customElements.get("et2-" + this.widget_type))
+				if(window.customElements.get("et2-" + this.widgetType))
 				{
-					this.widget_type = "et2-" + this.widget_type;
+					this.widgetType = "et2-" + this.widgetType;
 				}
 		}
 		// @ts-ignore TS doesn't know about this.getParent()
-		this.filter_node = <LitElement>loadWebComponent(this.widget_type, {...attrs, ...this.widget_options}, this);
+		this.filter_node = <LitElement>loadWebComponent(this.widgetType, {...attrs, ...this.widgetOptions}, this);
 		if(this.filter_node instanceof Et2Select)
 		{
 			this.filter_node.hoist = true;
@@ -83,10 +83,15 @@ export class Et2CustomFilterHeader extends FilterMixin(Et2InputWidget(LitElement
             <slot></slot>`;
 	}
 
-	get value() { return this.filter_node?.value || undefined;}
-
-	set value(new_value) { this.filter_node.value = new_value;}
+	get value()
+	{
+		return this.filter_node?.value || undefined;
+	}
 
+	set value(new_value)
+	{
+		this.filter_node.value = new_value;
+	}
 }
 
 customElements.define("et2-nextmatch-header-custom", Et2CustomFilterHeader);
\ No newline at end of file
diff --git a/api/js/etemplate/Et2Nextmatch/Headers/FilterMixin.ts b/api/js/etemplate/Et2Nextmatch/Headers/FilterMixin.ts
index 21888e5e39..33d390a37d 100644
--- a/api/js/etemplate/Et2Nextmatch/Headers/FilterMixin.ts
+++ b/api/js/etemplate/Et2Nextmatch/Headers/FilterMixin.ts
@@ -24,9 +24,9 @@ export const FilterMixin = <T extends Constructor>(superclass : T) => class exte
 		super.connectedCallback();
 
 		// Make sure there's an option for all
-		if(!this.empty_label && Array.isArray(this.select_options) && !this.select_options.find(o => o.value == ""))
+		if(!this.emptyLabel && Array.isArray(this.select_options) && !this.select_options.find(o => o.value == ""))
 		{
-			this.empty_label = this.label ? this.label : egw.lang("All");
+			this.emptyLabel = this.label ? this.label : egw.lang("All");
 		}
 
 		this.handleChange = this.handleChange.bind(this);
diff --git a/api/js/etemplate/Et2Select/Et2Select.ts b/api/js/etemplate/Et2Select/Et2Select.ts
index 30db7f51ac..614894e741 100644
--- a/api/js/etemplate/Et2Select/Et2Select.ts
+++ b/api/js/etemplate/Et2Select/Et2Select.ts
@@ -219,11 +219,11 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect)
 		// Only do this on once during initial setup, or it can be impossible to clear the value
 		const valueArray = Array.isArray(this.value) ? this.value : (!this.value ? [] : this.value.toString().split(','));
 
-		// value not in options --> use empty_label, if exists, or first option otherwise
+		// value not in options --> use emptyLabel, if exists, or first option otherwise
 		if(this.select_options.filter((option) => valueArray.find(val => val == option.value)).length === 0)
 		{
 			let oldValue = this.value;
-			this.value = this.empty_label ? "" : "" + this.select_options[0]?.value;
+			this.value = this.emptyLabel ? "" : "" + this.select_options[0]?.value;
 			// ""+ to cast value of 0 to "0", to not replace with ""
 			this.requestUpdate("value", oldValue);
 		}
@@ -285,7 +285,7 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect)
 	{
 		super.willUpdate(changedProperties);
 
-		if(changedProperties.has('select_options') || changedProperties.has("value") || changedProperties.has('empty_label'))
+		if(changedProperties.has('select_options') || changedProperties.has("value") || changedProperties.has('emptyLabel'))
 		{
 			this.fix_bad_value();
 
@@ -328,12 +328,12 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect)
 
 	_emptyLabelTemplate() : TemplateResult
 	{
-		if(!this.empty_label || this.multiple)
+		if(!this.emptyLabel || this.multiple)
 		{
 			return html``;
 		}
 		return html`
-            <sl-menu-item value="">${this.empty_label}</sl-menu-item>`;
+            <sl-menu-item value="">${this.emptyLabel}</sl-menu-item>`;
 	}
 
 	/**
diff --git a/api/js/etemplate/Et2Select/Et2SelectAccount.ts b/api/js/etemplate/Et2Select/Et2SelectAccount.ts
index fd602051d1..1e92e8f2fe 100644
--- a/api/js/etemplate/Et2Select/Et2SelectAccount.ts
+++ b/api/js/etemplate/Et2Select/Et2SelectAccount.ts
@@ -25,7 +25,7 @@ export class Et2SelectAccount extends Et2Select
 			/**
 			 * One of: 'accounts','groups','both','owngroups'
 			 */
-			account_type: String,
+			accountType: String,
 		}
 	}
 
@@ -35,19 +35,19 @@ export class Et2SelectAccount extends Et2Select
 		
 		this.searchUrl = "EGroupware\\Api\\Etemplate\\Widget\\Taglist::ajax_search";
 
-		this.__account_type = 'accounts';
+		this.__accountType = 'accounts';
 	}
 
-	set account_type(type : AccountType)
+	set accountType(type : AccountType)
 	{
-		this.__account_type = type;
+		this.__accountType = type;
 
 		super.select_options = this.select_options;
 	}
 
-	get account_type() : AccountType
+	get accountType() : AccountType
 	{
-		return this.__account_type;
+		return this.__accountType;
 	}
 
 	/**
@@ -62,9 +62,9 @@ export class Et2SelectAccount extends Et2Select
 		}
 		let select_options : Array<SelectOption>;
 		// for primary_group we only display owngroups == own memberships, not other groups
-		if (type === 'primary_group' && this.account_type !== 'accounts')
+		if (type === 'primary_group' && this.accountType !== 'accounts')
 		{
-			if (this.account_type === 'both')
+			if (this.accountType === 'both')
 			{
 				select_options = this.egw().accounts('accounts');
 			}
@@ -72,7 +72,7 @@ export class Et2SelectAccount extends Et2Select
 		}
 		else
 		{
-			select_options = this.egw().accounts(this.account_type);
+			select_options = this.egw().accounts(this.accountType);
 		}
 		return select_options;
 	}
diff --git a/api/js/etemplate/Et2Select/Et2SelectCategory.ts b/api/js/etemplate/Et2Select/Et2SelectCategory.ts
index 14b19c6f11..dcc5f725bd 100644
--- a/api/js/etemplate/Et2Select/Et2SelectCategory.ts
+++ b/api/js/etemplate/Et2Select/Et2SelectCategory.ts
@@ -50,7 +50,7 @@ export class Et2SelectCategory extends Et2StaticSelectMixin(Et2Select)
 			/**
 			 * Show categories below this parent category
 			 */
-			parent_cat: {type: Number}
+			parentCat: {type: Number}
 		}
 	}
 
@@ -153,4 +153,4 @@ export class Et2SelectCategory extends Et2StaticSelectMixin(Et2Select)
  */
 const so = new StaticOptions();
 
-customElements.define("et2-select-cat", Et2SelectCategory);
+customElements.define("et2-select-cat", Et2SelectCategory);
\ No newline at end of file
diff --git a/api/js/etemplate/Et2Select/Et2SelectEmail.ts b/api/js/etemplate/Et2Select/Et2SelectEmail.ts
index 5484f7bb9e..0756cff7c7 100644
--- a/api/js/etemplate/Et2Select/Et2SelectEmail.ts
+++ b/api/js/etemplate/Et2Select/Et2SelectEmail.ts
@@ -53,7 +53,7 @@ export class Et2SelectEmail extends Et2Select
 			/**
 			 * Show the full, original value email address under all circumstances, rather than the contact name for known contacts
 			 */
-			full_email: {type: Boolean}
+			fullEmail: {type: Boolean}
 		}
 	}
 
@@ -66,7 +66,7 @@ export class Et2SelectEmail extends Et2Select
 		this.editModeEnabled = true;
 		this.allowDragAndDrop = false;
 		this.multiple = true;
-		this.full_email = false;
+		this.fullEmail = false;
 		this.defaultValidators.push(new IsEmail());
 	}
 
@@ -165,7 +165,7 @@ export class Et2SelectEmail extends Et2Select
 	protected _createTagNode(item)
 	{
 		let tag = super._createTagNode(item);
-		tag.full_email = this.full_email;
+		tag.fullEmail = this.fullEmail;
 		if(!this.readonly && this.allowFreeEntries && this.allowDragAndDrop)
 		{
 			let dragTranslate = {x:0,y:0};
diff --git a/api/js/etemplate/Et2Select/Et2SelectReadonly.ts b/api/js/etemplate/Et2Select/Et2SelectReadonly.ts
index 4eac4c5f49..d5eca1ddab 100644
--- a/api/js/etemplate/Et2Select/Et2SelectReadonly.ts
+++ b/api/js/etemplate/Et2Select/Et2SelectReadonly.ts
@@ -164,7 +164,7 @@ li {
 	{
 		if(!this.value || Array.isArray(this.value) && !this.value.length)
 		{
-			return this._readonlyRender({label: this.empty_label, value: ""});
+			return this._readonlyRender({label: this.emptyLabel, value: ""});
 		}
 
 		return html`
diff --git a/api/js/etemplate/Et2Select/Et2WidgetWithSelectMixin.ts b/api/js/etemplate/Et2Select/Et2WidgetWithSelectMixin.ts
index 1f958417ad..bdc3c39c81 100644
--- a/api/js/etemplate/Et2Select/Et2WidgetWithSelectMixin.ts
+++ b/api/js/etemplate/Et2Select/Et2WidgetWithSelectMixin.ts
@@ -70,7 +70,7 @@ export const Et2widgetWithSelectMixin = <T extends Constructor<LitElement>>(supe
 				/**
 				 * Textual label for first row, eg: 'All' or 'None'.  It's value will be ''
 				 */
-				empty_label: String,
+				emptyLabel: String,
 
 				/**
 				 * Select box options
@@ -114,7 +114,7 @@ export const Et2widgetWithSelectMixin = <T extends Constructor<LitElement>>(supe
 			}
 
 			// Add in actual option tags to the DOM based on the new select_options
-			if(changedProperties.has('select_options') || changedProperties.has("empty_label"))
+			if(changedProperties.has('select_options') || changedProperties.has("emptyLabel"))
 			{
 				// Add in options as children to the target node
 				if(this._optionTargetNode)
@@ -195,7 +195,7 @@ export const Et2widgetWithSelectMixin = <T extends Constructor<LitElement>>(supe
 		 */
 		_emptyLabelTemplate() : TemplateResult
 		{
-			return html`${this.empty_label}`;
+			return html`${this.emptyLabel}`;
 		}
 
 		/**
diff --git a/api/js/etemplate/Et2Url/Et2Url.ts b/api/js/etemplate/Et2Url/Et2Url.ts
index aefb413f56..8b389e04bd 100644
--- a/api/js/etemplate/Et2Url/Et2Url.ts
+++ b/api/js/etemplate/Et2Url/Et2Url.ts
@@ -16,7 +16,7 @@ import {css} from "@lion/core";
 /**
  * @customElement et2-url
  *
- * @ToDo: implement allow_path attributes
+ * @ToDo: implement allowPath attributes
  */
 export class Et2Url extends Et2InvokerMixin(Et2Textbox)
 {
@@ -28,13 +28,13 @@ export class Et2Url extends Et2InvokerMixin(Et2Textbox)
 			/**
 			 * Allow a path instead of a URL, path must start with /, default false = not allowed
 			 */
-			allow_path: {
+			allowPath: {
 				type: Boolean,
 			},
 			/**
 			 * Require (or forbid) that the path ends with a /, default not checked
 			 */
-			trailing_slash: {
+			trailingSlash: {
 				type: Boolean,
 			},
 		};
@@ -62,14 +62,14 @@ export class Et2Url extends Et2InvokerMixin(Et2Textbox)
 		this._invokerAction = () => {
 			Et2Url.action(this.value);
 		}
-		this.allow_path = false;
-		this.trailing_slash = undefined;
+		this.allowPath = false;
+		this.trailingSlash = undefined;
 	}
 
 	/**
 	 * Change handler calling custom handler set via onchange attribute
 	 *
-	 * Reimplemented to add/remove trailing slash depending on trailing_slash attribute
+	 * Reimplemented to add/remove trailing slash depending on trailingSlash attribute
 	 *
 	 * @param _ev
 	 * @returns
@@ -77,9 +77,9 @@ export class Et2Url extends Et2InvokerMixin(Et2Textbox)
 	_oldChange(_ev: Event): boolean
 	{
 		const value = this.modelValue;
-		if (typeof this.trailing_slash !== 'undefined' && value && this.trailing_slash !== (value.substr(-1)==='/'))
+		if (typeof this.trailingSlash !== 'undefined' && value && this.trailingSlash !== (value.substr(-1)==='/'))
 		{
-			if (!this.trailing_slash)
+			if (!this.trailingSlash)
 			{
 				this.modelValue = value.replace(/\/+$/, '');
 			}
diff --git a/api/js/etemplate/Et2Url/Et2UrlEmailReadonly.ts b/api/js/etemplate/Et2Url/Et2UrlEmailReadonly.ts
index 2a1fd585b2..1bc381432d 100644
--- a/api/js/etemplate/Et2Url/Et2UrlEmailReadonly.ts
+++ b/api/js/etemplate/Et2Url/Et2UrlEmailReadonly.ts
@@ -25,14 +25,14 @@ export class Et2UrlEmailReadonly extends Et2UrlReadonly
 			/**
 			 * Show full email address if true otherwise show only name and put full address as statustext/tooltip
 			 */
-			full_email: {
+			fullEmail: {
 				type: Boolean,
 			},
 			/**
 			 * Show icon to add email as contact to addressbook
 			 * @ToDo
 			 */
-			contact_plus: {
+			contactPlus: {
 				type: Boolean,
 			},
 		};
@@ -42,7 +42,7 @@ export class Et2UrlEmailReadonly extends Et2UrlReadonly
 	{
 		this._value = val;
 		// check if we have a "name <email>" value and only show name
-		if (!this.full_email && val && val.indexOf('<') !== -1)
+		if (!this.fullEmail && val && val.indexOf('<') !== -1)
 		{
 			const parts = val.split('<');
 			if (parts[0])
diff --git a/api/js/etemplate/Et2Widget/Et2Widget.ts b/api/js/etemplate/Et2Widget/Et2Widget.ts
index d2e672185c..c90c9c69d0 100644
--- a/api/js/etemplate/Et2Widget/Et2Widget.ts
+++ b/api/js/etemplate/Et2Widget/Et2Widget.ts
@@ -174,7 +174,7 @@ const Et2WidgetMixin = <T extends Constructor>(superClass : T) =>
 				/**
 				 * Disable any translations for the widget
 				 */
-				no_lang: {
+				noLang: {
 					type: Boolean,
 					reflect: false
 				},
@@ -1399,7 +1399,7 @@ function transformAttributes(widget, mgr : et2_arrayMgr, attributes)
 				break;
 			default:
 				attrValue = mgr ? mgr.expandName("" + attrValue) : attrValue;
-				if(attrValue && typeof attrValue == "string" && !attributes.no_lang && widget_class.translate[attribute])
+				if(attrValue && typeof attrValue == "string" && !attributes.noLang && widget_class.translate[attribute])
 				{
 					// allow attribute to contain multiple translated sub-strings eg: {Firstname}.{Lastname}
 					if(attrValue.indexOf('{') !== -1)
diff --git a/api/js/etemplate/Expose/Et2DescriptionExpose.ts b/api/js/etemplate/Expose/Et2DescriptionExpose.ts
index 115d8f5c14..2331bf7e73 100644
--- a/api/js/etemplate/Expose/Et2DescriptionExpose.ts
+++ b/api/js/etemplate/Expose/Et2DescriptionExpose.ts
@@ -41,7 +41,7 @@ export class Et2DescriptionExpose extends ExposeMixin(Et2Description) implements
 			/**
 			 * hash for data stored on service-side with egw_link::(get|set)_data()
 			 */
-			mime_data: {type: String},
+			mimeData: {type: String},
 		}
 	}